/**
 * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Eclipse Public License (EPL).
 * Please see the license.txt included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */

package org.python.pydev.ui.wizards.files;

import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
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.DirectoryDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.codecompletion.revisited.PythonPathHelper;
import org.python.pydev.shared_core.structure.LinkedListWarningOnSlowOperations;
import org.python.pydev.utils.PyFileListing;

public class PythonExistingSourceGroup {

    private Text singleSelectionText;
    private Button singleBrowseButton;

    private IPath linkTarget;

    protected String errorMessage;
    protected String warningMessage;

    public String getErrorMessage() {
        return errorMessage;
    }

    public String getWarningMessage() {
        return warningMessage;
    }

    protected void clearAllProblems() {
        errorMessage = null;
        warningMessage = null;
    }

    /**
     * The source paths that are already referenced by the project.
     */
    protected List<IPath> projectLinkTargets = new LinkedListWarningOnSlowOperations<IPath>();
    protected IProject iProject;

    public PythonExistingSourceGroup(Composite parent, IProject project, ModifyListener sourceChangeListener) {
        createContents(parent, sourceChangeListener);
        setActiveProject(project);
    }

    /**
     * Use this constructor only when extending with {@link PythonExistingSourceListGroup}.
     */
    protected PythonExistingSourceGroup() {
    }

    /**
     * Tell this group what the active project is. Doing so will update its list of linked source paths
     * that are already included in the project, which is necessary for proper conflict-checking. 
     * @param project
     */
    public void setActiveProject(IProject project) {
        if (iProject == project) {
            return;
        }

        iProject = project;
        projectLinkTargets.clear();

        if (project != null) {
            try {
                IResource[] members = project.members();
                for (IResource member : members) {
                    if (member.isLinked()) {
                        projectLinkTargets.add(member.getLocation());
                    }
                }
            } catch (CoreException e) {
                Log.log(e);
            }
            conflictCheck();
        }
    }

    protected void conflictCheck() {
        clearAllProblems();
        selectLinkTarget(Path.fromOSString(singleSelectionText.getText()));
    }

    private void createContents(final Composite parent, ModifyListener sourceChangeListener) {
        Font font = parent.getFont();

        Group group = new Group(parent, SWT.NONE);
        //setControl(group);
        GridLayout topLayout = new GridLayout();
        topLayout.numColumns = 2;
        group.setLayout(topLayout);
        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        group.setLayoutData(gd);
        group.setFont(font);
        group.setText("Location of existing source");

        singleSelectionText = new Text(group, SWT.SINGLE | SWT.BORDER);
        gd = new GridData(GridData.FILL_HORIZONTAL);
        singleSelectionText.setLayoutData(gd);
        singleSelectionText.setFont(font);
        singleSelectionText.addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(ModifyEvent evt) {
                clearAllProblems();
                selectLinkTarget(Path.fromOSString(singleSelectionText.getText()));
            }
        });

        singleBrowseButton = new Button(group, SWT.PUSH);
        singleBrowseButton.setText("Browse...");

        singleBrowseButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                DirectoryDialog dialog = new DirectoryDialog(parent.getShell());
                String selection = dialog.open();
                if (selection != null) {
                    singleSelectionText.setText(selection);
                }
            }
        });

        singleSelectionText.addModifyListener(sourceChangeListener);
    }

    /**
     * Add the selected folder path to the list of all chosen paths. While doing so, check for conflicts.
     * Issue a warning for the following selections:
     *  -folders that are subdirectories of other chosen folders, or contain other chosen folders
     *  -folders that have no .py files in them, or in one of their subdirectories
     *  
     * Issue an error if the selection contains the destination of the link to be created. Don't add
     * the selection to the list of source paths in case of an error.
     */
    protected void selectLinkTarget(IPath linkPath) {
        if (validateLinkPath(linkPath)) {
            linkTarget = linkPath;
        } else {
            linkTarget = null;
        }
    }

    protected boolean validateLinkPath(IPath linkPath) {
        if (!linkPath.toFile().exists()) {
            String segment = linkPath.lastSegment();
            if (segment == null) {
                errorMessage = "External source location must not be null.";
            } else {
                errorMessage = "External source location '" + segment + "' does not exist.";
            }
            return false;
        }

        IPath rootPath = (iProject == null ? ResourcesPlugin.getWorkspace().getRoot() : iProject).getLocation();
        if (linkPath.isPrefixOf(rootPath) || (iProject != null && rootPath.isPrefixOf(linkPath))) {
            errorMessage = "External source location '" + linkPath.lastSegment()
                    + "' overlaps with the project directory.";
            return false;
        }

        for (IPath otherPath : projectLinkTargets) {
            if (linkPath.isPrefixOf(otherPath) || otherPath.isPrefixOf(linkPath)) {
                warningMessage = "Location '" + linkPath.lastSegment()
                        + "' overlaps with the project resource '"
                        + otherPath.lastSegment()
                        + "'. This can cause unexpected side-effects.";
                break;
            }
        }

        PyFileListing pyFileListing = PythonPathHelper.getModulesBelow(linkPath.toFile(), null);
        if (pyFileListing == null || pyFileListing.getFoundPyFileInfos().size() == 0) {
            warningMessage = "Folder '" + linkPath.lastSegment()
                    + "' does not contain any Python files.";
        }

        return true;
    }

    /**
     * Return the selected source.
     * @return
     */
    public IPath getLinkTarget() {
        return linkTarget;
    }
}
