/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.wtp.releng.tools.component.ui.internal.editor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.pde.core.plugin.IFragmentModel;
import org.eclipse.pde.core.plugin.IPluginModel;
import org.eclipse.pde.internal.ui.wizards.PluginSelectionDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
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.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.FormPage;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.wtp.releng.tools.component.internal.ComponentDepends;
import org.eclipse.wtp.releng.tools.component.internal.ComponentRef;
import org.eclipse.wtp.releng.tools.component.internal.ComponentXML;
import org.eclipse.wtp.releng.tools.component.internal.Description;
import org.eclipse.wtp.releng.tools.component.internal.Plugin;
import org.eclipse.wtp.releng.tools.component.ui.ComponentManager;

public class ComponentPage extends FormPage
{
  public static final String ID = "org.eclipse.wtp.releng.tools.component.ui.internal.editor.ComponentPage";
  private final Color BLUE = new Color(Display.getDefault(), 0, 0, 255);
  private final char KEY_DEL = 127; 

  private Text name;
  private Text overviewURL;
  private Button unrestrictedDepends;
  private Button addCompRef;
  private Tree compRefs;
  private Tree plugins;
  private TreeViewer compRefsViewer;
  private TreeViewer pluginsViewer;

  public ComponentPage(FormEditor editor, String id, String title)
  {
    super(editor, id, title);
  }

  public ComponentPage(String id, String title)
  {
    super(id, title);
  }

  private void init()
  {
    ComponentXMLEditor editor = (ComponentXMLEditor)getEditor();
    ComponentXML compXML = editor.getComponentXML();
    String compName = compXML.getName();
    name.setText(compName != null ? compName : "");
    Description description = compXML.getDescription();
    overviewURL.setText(description != null && description.getUrl() != null ? description.getUrl() : "");
    ComponentDepends depends = compXML.getComponentDepends();
    boolean isUnrestricted = depends.isUnrestricted();
    unrestrictedDepends.setSelection(isUnrestricted);
    addCompRef.setEnabled(!isUnrestricted);
    compRefsViewer = new TreeViewer(compRefs);
    ComponentXMLProvider compRefsProvider = new ComponentXMLProvider(ComponentXMLProvider.SHOW_COMPONENT_REFS);
    compRefsViewer.setContentProvider(compRefsProvider);
    compRefsViewer.setLabelProvider(compRefsProvider);
    compRefsViewer.setInput(depends);
    pluginsViewer = new TreeViewer(plugins);
    ComponentXMLProvider pluginsProvider = new ComponentXMLProvider(ComponentXMLProvider.SHOW_PLUGINS);
    pluginsViewer.setContentProvider(pluginsProvider);
    pluginsViewer.setLabelProvider(pluginsProvider);
    pluginsViewer.setInput(compXML);
    editor.setDirty(false);
  }

  protected void createFormContent(IManagedForm managedForm)
  {
    ComponentManager manager = ComponentManager.getManager();
    super.createFormContent(managedForm);
    ScrolledForm form = managedForm.getForm();
    form.setText(manager.getMessage("PAGE_COMPONENT"));
    Composite body = form.getBody();
    GridLayout gl = new GridLayout();
    gl.numColumns = 2;
    gl.makeColumnsEqualWidth = true;
    gl.marginWidth = 10;
    gl.verticalSpacing = 20;
    gl.horizontalSpacing = 20;
    body.setLayout(gl);
    FormToolkit toolkit = managedForm.getToolkit();
    createLeftColumn(managedForm, toolkit.createComposite(body));
    createRightColumn(managedForm, toolkit.createComposite(body));
    toolkit.paintBordersFor(body);
    init();
  }

  private void createLeftColumn(IManagedForm managedForm, Composite parent)
  {
    GridLayout gl = new GridLayout();
    gl.numColumns = 1;
    gl.marginWidth = 5;
    gl.marginHeight = 5;
    gl.verticalSpacing = 10;
    parent.setLayout(gl);
    parent.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_VERTICAL));
    FormToolkit toolkit = managedForm.getToolkit();
    Composite generalInfo = toolkit.createComposite(parent);
    Composite compDepends = toolkit.createComposite(parent);
    createGeneralInfo(managedForm, generalInfo);
    createComponentDepends(managedForm, compDepends);
    toolkit.paintBordersFor(parent);
  }

  private void createRightColumn(IManagedForm managedForm, Composite parent)
  {
    createPlugins(managedForm, parent);
  }

  private void createGeneralInfo(IManagedForm managedForm, Composite parent)
  {
    GridLayout gl = new GridLayout();
    gl.numColumns = 1;
    gl.marginWidth = 1;
    gl.marginHeight = 5;
    parent.setLayout(gl);
    GridData gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
    parent.setLayoutData(gd);
    ComponentManager manager = ComponentManager.getManager();
    FormToolkit toolkit = managedForm.getToolkit();
    toolkit.createLabel(parent, manager.getMessage("SECTION_DESC_GENERAL_INFO"));
    Composite innerComposite = toolkit.createComposite(parent);
    GridLayout gl2 = new GridLayout();
    gl2.numColumns = 2;
    gl2.marginWidth = 1;
    gl2.marginHeight = 1;
    innerComposite.setLayout(gl2);
    innerComposite.setLayoutData(gd);
    Label nameLabel = toolkit.createLabel(innerComposite, manager.getMessage("LABEL_NAME"));
    nameLabel.setForeground(BLUE);
    Composite nameComposite = toolkit.createComposite(innerComposite);
    nameComposite.setLayout(gl);
    nameComposite.setLayoutData(gd);
    name = toolkit.createText(nameComposite, "");
    name.setLayoutData(gd);
    name.addModifyListener
    (
      new ModifyListener()
      {
        public void modifyText(ModifyEvent event)
        {
          modifyNameEvent(event);
        }
      }
    );
    Label overviewURLLabel = toolkit.createLabel(innerComposite, manager.getMessage("LABEL_OVERVIEW_URL"));
    overviewURLLabel.setForeground(BLUE);
    Composite overviewURLComposite = toolkit.createComposite(innerComposite);
    overviewURLComposite.setLayout(gl);
    overviewURLComposite.setLayoutData(gd);
    overviewURL = toolkit.createText(overviewURLComposite, "");
    overviewURL.setLayoutData(gd);
    overviewURL.addModifyListener
    (
      new ModifyListener()
      {
        public void modifyText(ModifyEvent event)
        {
          modifyOverviewURLEvent(event);
        }
      }
    );
    toolkit.paintBordersFor(nameComposite);
    toolkit.paintBordersFor(overviewURLComposite);
    toolkit.paintBordersFor(innerComposite);
    toolkit.paintBordersFor(parent);
  }

  private void createComponentDepends(IManagedForm managedForm, Composite parent)
  {
    GridLayout gl = new GridLayout();
    gl.numColumns = 1;
    gl.marginWidth = 1;
    gl.marginHeight = 6;
    parent.setLayout(gl);
    GridData gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_VERTICAL);
    parent.setLayoutData(gd);
    ComponentManager manager = ComponentManager.getManager();
    FormToolkit toolkit = managedForm.getToolkit();
    toolkit.createLabel(parent, manager.getMessage("SECTION_DESC_COMPONENT_DEPENDS"));
    unrestrictedDepends = toolkit.createButton(parent, manager.getMessage("LABEL_UNRESTRICTED_COMPONENT_DEPENDS"), SWT.CHECK);
    unrestrictedDepends.addSelectionListener
    (
      new SelectionListener()
      {
        public void widgetSelected(SelectionEvent event)
        {
          unrestrictedDependsEvent(event);
        }
        public void widgetDefaultSelected(SelectionEvent event)
        {
          unrestrictedDependsEvent(event);
        }
      }
    );
    toolkit.createLabel(parent, manager.getMessage("LABEL_COMPONENT_REFS"));
    Composite compRefsComposite = toolkit.createComposite(parent);
    GridLayout gl2 = new GridLayout();
    gl2.numColumns = 2;
    gl2.marginWidth = 1;
    gl2.marginHeight = 1;
    compRefsComposite.setLayout(gl2);
    compRefsComposite.setLayoutData(gd);
    compRefs = toolkit.createTree(compRefsComposite, SWT.MULTI);
    compRefs.setLayout(gl);
    compRefs.setLayoutData(gd);
    compRefs.addKeyListener
    (
      new KeyListener()
      {
        public void keyPressed(KeyEvent event)
        {
          // do nothing
        }
        public void keyReleased(KeyEvent event)
        {
          compRefKeyEvent(event);
        }
      }
    );
    addCompRef = toolkit.createButton(compRefsComposite, manager.getMessage("LABEL_ADD"), SWT.PUSH);
    addCompRef.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
    addCompRef.addSelectionListener
    (
      new SelectionListener()
      {
        public void widgetSelected(SelectionEvent event)
        {
          addCompRefEvent(event);
        }
        public void widgetDefaultSelected(SelectionEvent event)
        {
          addCompRefEvent(event);
        }
      }
    );
    toolkit.paintBordersFor(compRefsComposite);
    toolkit.paintBordersFor(parent);
  }

  private void createPlugins(IManagedForm managedForm, Composite parent)
  {
    GridLayout gl = new GridLayout();
    gl.numColumns = 1;
    gl.marginWidth = 1;
    gl.marginHeight = 6;
    parent.setLayout(gl);
    GridData gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_VERTICAL);
    parent.setLayoutData(gd);
    ComponentManager manager = ComponentManager.getManager();
    FormToolkit toolkit = managedForm.getToolkit();
    toolkit.createLabel(parent, manager.getMessage("SECTION_DESC_PLUGINS"));
    toolkit.createLabel(parent, manager.getMessage("LABEL_PLUGINS"));
    Composite pluginsComposite = toolkit.createComposite(parent);
    GridLayout gl2 = new GridLayout();
    gl2.numColumns = 2;
    gl2.marginWidth = 1;
    gl2.marginHeight = 1;
    pluginsComposite.setLayout(gl2);
    pluginsComposite.setLayoutData(gd);
    plugins = toolkit.createTree(pluginsComposite, SWT.MULTI);
    plugins.setLayout(gl);
    plugins.setLayoutData(gd);
    plugins.addKeyListener
    (
      new KeyListener()
      {
        public void keyPressed(KeyEvent event)
        {
          // do nothing
        }
        public void keyReleased(KeyEvent event)
        {
          pluginKeyEvent(event);
        }
      }
    );
    Button addPlugin = toolkit.createButton(pluginsComposite, manager.getMessage("LABEL_ADD"), SWT.PUSH);
    addPlugin.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
    addPlugin.addSelectionListener
    (
      new SelectionListener()
      {
        public void widgetSelected(SelectionEvent event)
        {
          addPluginEvent(event);
        }
        public void widgetDefaultSelected(SelectionEvent event)
        {
          addPluginEvent(event);
        }
      }
    );
    toolkit.paintBordersFor(pluginsComposite);
    toolkit.paintBordersFor(parent);
  }

  private void modifyNameEvent(ModifyEvent event)
  {
    ComponentXMLEditor editor = (ComponentXMLEditor)getEditor();
    editor.getComponentXML().setName(name.getText());
    editor.setDirty(true);
  }

  private void modifyOverviewURLEvent(ModifyEvent event)
  {
    ComponentXMLEditor editor = (ComponentXMLEditor)getEditor();
    ComponentXML compXML = editor.getComponentXML();
    Description description = compXML.getDescription();
    if (description == null)
    {
      description = new Description();
      compXML.setDescription(description);
    }
    description.setUrl(overviewURL.getText());
    editor.setDirty(true);
  }

  private void unrestrictedDependsEvent(SelectionEvent event)
  {
    boolean isUnrestricted = unrestrictedDepends.getSelection();
    compRefs.setEnabled(!isUnrestricted);
    addCompRef.setEnabled(!isUnrestricted);
    ComponentXMLEditor editor = ((ComponentXMLEditor)getEditor());
    editor.getComponentXML().getComponentDepends().setUnrestricted(isUnrestricted ? Boolean.TRUE : Boolean.FALSE);
    editor.setDirty(true);
  }

  private void compRefKeyEvent(KeyEvent event)
  {
    if (event.character == KEY_DEL) 
    {
      TreeItem[] items = compRefs.getSelection();
      if (items.length > 0)
      {
        ComponentXMLEditor editor = (ComponentXMLEditor)getEditor();
        Collection refs = editor.getComponentXML().getComponentDepends().getComponentRefs();
        for (int i = 0; i < items.length; i++)
        {
          refs.remove(items[i].getData());
        }
        compRefsViewer.refresh();
        editor.setDirty(true);
      }
    }
  }

  private void addCompRefEvent(SelectionEvent event)
  {
    ComponentXMLEditor editor = (ComponentXMLEditor)getEditor();
    ComponentDepends depends = editor.getComponentXML().getComponentDepends();
    Collection refs = depends.getComponentRefs();
    List ignoreNames = new ArrayList(refs.size() + 1);
    for (Iterator it = refs.iterator(); it.hasNext();)
      ignoreNames.add(((ComponentRef)it.next()).getName());
    ignoreNames.add(name.getText());
    ComponentRefDialog dialog = new ComponentRefDialog(getEditor().getSite().getShell(), ignoreNames);
    if (dialog.open() == Dialog.OK)
    {
      String[] compNames = dialog.getCompNames();
      if (compNames.length > 0)
      {
        for (int i = 0; i < compNames.length; i++)
        {
          ComponentRef ref = new ComponentRef();
          ref.setName(compNames[i]);
          refs.add(ref);
        }
        editor.setDirty(true);
        compRefsViewer.refresh();
      }
    }
  }

  private void pluginKeyEvent(KeyEvent event)
  {
    if (event.character == KEY_DEL) 
    {
      TreeItem[] items = plugins.getSelection();
      if (items.length > 0)
      {
        ComponentXMLEditor editor = (ComponentXMLEditor)getEditor();
        Collection pluginList = editor.getComponentXML().getPlugins();
        for (int i = 0; i < items.length; i++)
        {
          pluginList.remove(items[i].getData());
        }
        pluginsViewer.refresh();
        editor.setDirty(true);
      }
    }
  }

  private void addPluginEvent(SelectionEvent event)
  {
    PluginSelectionDialog dialog = new PluginSelectionDialog(getEditor().getSite().getShell(), true, true);
    if (dialog.open() == Dialog.OK)
    {
      Object[] results = dialog.getResult();
      if (results.length > 0)
      {
        ComponentXMLEditor editor = (ComponentXMLEditor)getEditor();
        Collection pluginList = editor.getComponentXML().getPlugins();
        boolean added = false;
        for (int i = 0; i < results.length; i++)
        {
          if (results[i] instanceof IPluginModel)
          {
            String pluginId = ((IPluginModel)results[i]).getPlugin().getId();
            if (isNewPlugin(pluginId))
            {
              Plugin plugin = new Plugin();
              plugin.setId(pluginId);
              plugin.setFragment(Boolean.FALSE);
              pluginList.add(plugin);
              added = true;
            }
          }
          else if (results[i] instanceof IFragmentModel)
          {
            String fragmentId = ((IFragmentModel)results[i]).getFragment().getId();
            if (isNewPlugin(fragmentId))
            {
              Plugin fragment = new Plugin();
              fragment.setId(fragmentId);
              fragment.setFragment(Boolean.TRUE);
              pluginList.add(fragment);
              added = true;
            }
          }
        }
        if (added)
        {
          pluginsViewer.refresh();
          editor.setDirty(true);
        }
      }
    }
  }

  private boolean isNewPlugin(String pluginId)
  {
    TreeItem[] items = plugins.getItems();
    for (int i = 0; i < items.length; i++)
      if (items[i].getText().equals(pluginId))
        return false;
    return true;
  }
}
