/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.sdkuilib.internal.repository.sdkman1;

import com.android.sdklib.internal.repository.Archive;
import com.android.sdklib.internal.repository.IDescription;
import com.android.sdklib.internal.repository.Package;
import com.android.sdkuilib.internal.repository.UpdaterData;
import com.android.sdkuilib.internal.repository.UpdaterPage;
import com.android.sdkuilib.repository.ISdkChangeListener;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import java.io.File;

/**
 * Page that displays all locally installed packages from the current SDK.
 */
public class LocalPackagesPage extends UpdaterPage implements ISdkChangeListener {

    private final UpdaterData mUpdaterData;

    private Label mSdkLocLabel;
    private TableViewer mTableViewerPackages;
    private Table mTablePackages;
    private TableColumn mColumnPackages;
    private Group mDescriptionContainer;
    private Composite mContainerButtons;
    private Button mUpdateButton;
    private Label mPlaceholder1;
    private Button mDeleteButton;
    private Label mPlaceholder2;
    private Button mRefreshButton;
    private Label mDescriptionLabel;


    /**
     * Create the composite.
     * @param parent The parent of the composite.
     * @param updaterData An instance of {@link UpdaterData}.
     */
    public LocalPackagesPage(Composite parent, int swtStyle, UpdaterData updaterData) {
        super(parent, swtStyle);

        mUpdaterData = updaterData;

        createContents(this);
        postCreate();  //$hide$
    }

    private void createContents(Composite parent) {
        parent.setLayout(new GridLayout(3, false));

        mSdkLocLabel = new Label(parent, SWT.NONE);
        mSdkLocLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 3, 1));
        mSdkLocLabel.setText("SDK Location: " +
                (mUpdaterData.getOsSdkRoot() != null ? mUpdaterData.getOsSdkRoot()
                                                     : "<unknown>"));

        mTableViewerPackages = new TableViewer(parent, SWT.BORDER | SWT.FULL_SELECTION);
        mTablePackages = mTableViewerPackages.getTable();
        mTablePackages.setHeaderVisible(true);
        mTablePackages.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
        mTablePackages.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                onTreeSelected(); //$hide$
            }
        });

        mColumnPackages = new TableColumn(mTablePackages, SWT.NONE);
        mColumnPackages.setWidth(377);
        mColumnPackages.setText("Installed packages");

        mDescriptionContainer = new Group(parent, SWT.NONE);
        mDescriptionContainer.setLayout(new GridLayout(1, false));
        mDescriptionContainer.setText("Description");
        mDescriptionContainer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));

        mDescriptionLabel = new Label(mDescriptionContainer, SWT.NONE);
        mDescriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true, 1, 1));
        mDescriptionLabel.setText("Line1\nLine2\nLine3");

        mContainerButtons = new Composite(parent, SWT.NONE);
        mContainerButtons.setLayout(new GridLayout(5, false));
        mContainerButtons.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));

        mUpdateButton = new Button(mContainerButtons, SWT.NONE);
        mUpdateButton.setText("Update All...");
        mUpdateButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                onUpdateSelected();  //$hide$ (hide from SWT designer)
            }
        });

        mPlaceholder1 = new Label(mContainerButtons, SWT.NONE);
        mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));

        mDeleteButton = new Button(mContainerButtons, SWT.NONE);
        mDeleteButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
        mDeleteButton.setText("Delete...");
        mDeleteButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                onDeleteSelected();  //$hide$ (hide from SWT designer)
            }
        });

        mPlaceholder2 = new Label(mContainerButtons, SWT.NONE);
        mPlaceholder2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));

        mRefreshButton = new Button(mContainerButtons, SWT.NONE);
        mRefreshButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
        mRefreshButton.setText("Refresh");
        mRefreshButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                onRefreshSelected();  //$hide$ (hide from SWT designer)
            }
        });
    }

    @Override
    public void dispose() {
        mUpdaterData.removeListener(this);
        super.dispose();
    }

    @Override
    protected void checkSubclass() {
        // Disable the check that prevents subclassing of SWT components
    }

    // -- Start of internal part ----------
    // Hide everything down-below from SWT designer
    //$hide>>$

    /**
     * Called by the constructor right after {@link #createContents(Composite)}.
     */
    private void postCreate() {
        mUpdaterData.addListeners(this);
        adjustColumnsWidth();
        updateButtonsState();
    }

    /**
     * Adds a listener to adjust the columns width when the parent is resized.
     * <p/>
     * If we need something more fancy, we might want to use this:
     * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet77.java?view=co
     */
    private void adjustColumnsWidth() {
        // Add a listener to resize the column to the full width of the table
        ControlAdapter resizer = new ControlAdapter() {
            @Override
            public void controlResized(ControlEvent e) {
                Rectangle r = mTablePackages.getClientArea();
                mColumnPackages.setWidth(r.width);
            }
        };
        mTablePackages.addControlListener(resizer);
        resizer.controlResized(null);
    }

    /**
     * Enable or disable buttons depending on list content and selection
     */
    private void updateButtonsState() {
        ISelection sel = mTableViewerPackages.getSelection();
        boolean hasSelection = sel != null && !sel.isEmpty();

        mUpdateButton.setEnabled(mTablePackages.getItemCount() > 0);
        mDeleteButton.setEnabled(hasSelection);
        mRefreshButton.setEnabled(true);
    }

    /**
     * Called when an item in the package table viewer is selected.
     * If the items is an {@link IDescription} (as it should), this will display its long
     * description in the description area. Otherwise when the item is not of the expected
     * type or there is no selection, it empties the description area.
     */
    private void onTreeSelected() {
        updateButtonsState();

        ISelection sel = mTableViewerPackages.getSelection();
        if (sel instanceof IStructuredSelection) {
            Object elem = ((IStructuredSelection) sel).getFirstElement();
            if (elem instanceof IDescription) {
                mDescriptionLabel.setText(((IDescription) elem).getLongDescription());
                mDescriptionContainer.layout(true);
                return;
            }
        }
        mDescriptionLabel.setText("");  //$NON-NLS1-$
    }

    /** User selected the 'update all' button. */
    private void onUpdateSelected() {
        mUpdaterData.updateOrInstallAll_WithGUI(
                null /*selectedArchives*/,
                false /* includeObsoletes */,
                0 /* flags */);
    }

    private void onDeleteSelected() {
        ISelection sel = mTableViewerPackages.getSelection();
        if (sel instanceof IStructuredSelection) {
            Object elem = ((IStructuredSelection) sel).getFirstElement();
            if (elem instanceof Package) {

                String title = "Delete SDK Package";
                String error = null;

                Package p = (Package) elem;
                Archive[] archives = p.getArchives();
                if (archives.length == 1 && archives[0] != null && archives[0].isLocal()) {
                    Archive archive = archives[0];
                    String osPath = archive.getLocalOsPath();

                    File dir = new File(osPath);
                    if (dir.isDirectory()) {
                        String msg = String.format("Are you sure you want to delete '%1$s' at '%2$s'? This cannot be undone.",
                                p.getShortDescription(), osPath);

                        if (MessageDialog.openQuestion(getShell(), title, msg)) {
                            archive.deleteLocal();

                            // refresh list
                            onRefreshSelected();
                        }
                    } else {
                        error = "Directory not found for this package";
                    }
                } else {
                    error = "No local archive found for this package";
                }

                if (error != null) {
                    MessageDialog.openError(getShell(), title, error);
                }

                return;
            }
        }
    }

    private void onRefreshSelected() {
        mUpdaterData.reloadSdk();
        updateButtonsState();
    }

    // --- Implementation of ISdkChangeListener ---

    public void onSdkLoaded() {
        onSdkReload();
    }

    public void onSdkReload() {
        LocalSdkAdapter localSdkAdapter = mUpdaterData.getLocalSdkAdapter();
        mTableViewerPackages.setLabelProvider(  localSdkAdapter.getLabelProvider());
        mTableViewerPackages.setContentProvider(localSdkAdapter.getContentProvider());
        mTableViewerPackages.setInput(localSdkAdapter);
        onTreeSelected();
    }

    public void preInstallHook() {
        // nothing to be done for now.
    }

    public void postInstallHook() {
        // nothing to be done for now.
    }

    // End of hiding from SWT Designer
    //$hide<<$
}
