/*
 * Licensed Materials - Property of Perforce Software, Inc. 
 * © Copyright Perforce Software, Inc. 2014, 2021 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */
package utils.sdm;

import java.awt.Container;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;

import javax.swing.JComboBox;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;

import ilog.views.IlvApplyObject;
import ilog.views.IlvGraphic;
import ilog.views.io.IlvInputStream;
import ilog.views.io.IlvPersistentObject;
import ilog.views.io.IlvReadFileException;
import ilog.views.maps.IlvMapUtil;
import ilog.views.maps.symbology.swing.IlvAbstractGroupTreeViewActions;
import ilog.views.maps.symbology.swing.IlvSymbologyTreeView;
import ilog.views.maps.symbology.swing.IlvSymbologyTreeViewActions;
import ilog.views.maps.symbology.swing.IlvTablePersistentContext;
import ilog.views.sdm.IlvSDMModel;
import ilog.views.util.swing.IlvSwingUtil;

/**
 * Class that combines actions from more than one single
 * <code>IlvSymbologyTreeViewActions</code> This class relies on the fact that
 * each symbol tag (as per {@link IlvSDMModel#getTag(Object)}) is assoiated to
 * only a single actions class.
 */
public class CombinedTreeViewActions extends IlvAbstractGroupTreeViewActions {
  // association between symbol tags and actions instance.
  final private Hashtable<String, IlvSymbologyTreeViewActions> association = new Hashtable<String, IlvSymbologyTreeViewActions>();
  // table of actions instance.
  final private IlvSymbologyTreeViewActions[] actionTable;
  // should this class show a popup menu to select the type of symbol ?
  static boolean usePopup = true;
  // popup penu created.
  private JPopupMenu pm;

  // JV-6361
  /**
   * Class used to store and retrieve the persistent context of each action. For
   * compatibility reason (to load files created before 8.7).
   * 
   * @deprecated Since JViews 8.8, this is replaced by
   *             <code>IlvTablePersistentContext</code>
   */
  static public class TableContext extends IlvTablePersistentContext {
    /**
     * Creates a new <code>TableContext</code>.
     * 
     * @param stream
     *          input stream
     * @throws IlvReadFileException
     */
    public TableContext(IlvInputStream stream) throws IlvReadFileException {
      super(stream);
    }
  }

  /**
   * Creates a new <code>CombinedTreeViewActions</code>.
   * 
   * @param actionTable
   *          table of the actions that the user can choose from.
   */
  public CombinedTreeViewActions(IlvSymbologyTreeViewActions[] actionTable) {
    this.actionTable = actionTable;
  }

  /** {@inheritDoc} */
  Override
  public void actOnSymbologyChanged() {
    // not implemented
  }

  /** {@inheritDoc} */
  Override
  public void createSymbol(final IlvSDMModel model, final Object group, final IlvApplyObject applier) {
    if (usePopup) {
      if (pm == null) {
        pm = new JPopupMenu();
        for (int i = 0; i < actionTable.length; i++) {
          final IlvSymbologyTreeViewActions action = actionTable[i];
          JMenuItem b = new JMenuItem(actionTable[i].toString());
          b.addActionListener(new ActionListener() {
            Override
            public void actionPerformed(ActionEvent e) {
              IlvApplyObject applier2 = new IlvApplyObject() {
                Override
                public void apply(IlvGraphic obj, Object node) {
                  applier.apply(obj, node);
                  setNodeAction(model.getTag(node), action);
                }
              };
              action.createSymbol(model, group, applier2);
            }
          });
          pm.add(b);
        }
      }
      Point p = getView().getMousePosition(true);
      if (p == null) {
        Container tl = getView().getTopLevelAncestor();
        p = tl.getMousePosition(true);
        if (p == null) {
          pm.show(getView(), 0, 0);
        } else {
          p = IlvSwingUtil.convertPoint(tl, p, getView());
          pm.show(getView(), p.x, p.y);
        }
      } else {
        pm.show(getView(), p.x, p.y);
      }
    } else {
      JComboBox<IlvSymbologyTreeViewActions> combo = new JComboBox<IlvSymbologyTreeViewActions>(actionTable);
      int ans = JOptionPane.showConfirmDialog(getView(), combo,
          IlvMapUtil.getString(CombinedTreeViewActions.class, "CombinedTreeViewActions.choseSymbolType"), //$NON-NLS-1$
          JOptionPane.OK_CANCEL_OPTION);
      if (ans == JOptionPane.OK_OPTION) {
        final IlvSymbologyTreeViewActions action = actionTable[combo.getSelectedIndex()];
        IlvApplyObject applier2 = new IlvApplyObject() {
          Override
          public void apply(IlvGraphic obj, Object node) {
            applier.apply(obj, node);
            setNodeAction(model.getTag(node), action);
          }
        };
        action.createSymbol(model, group, applier2);
      }
    }
  }

  /** {@inheritDoc} */
  Override
  public Object dropSymbolAt(IlvSDMModel model, Object data, Double lonRad, Double latRad) {
    for (int i = 0; i < actionTable.length; i++) {
      Object node = actionTable[i].dropSymbolAt(model, data, lonRad, latRad);
      if (node != null) {
        setNodeAction(model.getTag(node), actionTable[i]);
        return node;
      }
    }
    return null;
  }

  /** {@inheritDoc} */
  Override
  public Object duplicateSymbol(IlvSDMModel model, Object node) {
    IlvSymbologyTreeViewActions actions = getNodeAction(model.getTag(node));
    if (actions != null) {
      Object duplicatedNode = actions.duplicateSymbol(model, node);
      setNodeAction(model.getTag(duplicatedNode), actions);
      return duplicatedNode;
    }
    return null;
  }

  /** {@inheritDoc} */
  Override
  public void editSymbol(IlvSDMModel model, Object node, IlvApplyObject applier) {
    IlvSymbologyTreeViewActions actions = getNodeAction(model.getTag(node));
    if (actions != null) {
      actions.editSymbol(model, node, applier);
    }
  }

  /** {@inheritDoc} */
  Override
  public void editSymbology(IlvSDMModel model, IlvApplyObject applier) {
    // not implemented
  }

  /** {@inheritDoc} */
  Override
  public boolean isCreateSymbolEnabled(IlvSDMModel model) {
    for (int i = 0; i < actionTable.length; i++) {
      if (actionTable[i].isCreateSymbolEnabled(model)) {
        return true;
      }
    }
    return false;
  }

  /** {@inheritDoc} */
  Override
  public boolean isDuplicateSymbolEnabled(IlvSDMModel model) {
    for (int i = 0; i < actionTable.length; i++) {
      if (actionTable[i].isDuplicateSymbolEnabled(model)) {
        return true;
      }
    }
    return false;
  }

  /** {@inheritDoc} */
  Override
  public boolean isEditSymbolEnabled(IlvSDMModel model) {
    for (int i = 0; i < actionTable.length; i++) {
      if (actionTable[i].isEditSymbolEnabled(model)) {
        return true;
      }
    }
    return false;
  }

  /** {@inheritDoc} */
  Override
  public boolean isEditSymbologyEnabled(IlvSDMModel model) {
    for (int i = 0; i < actionTable.length; i++) {
      if (actionTable[i].isEditSymbologyEnabled(model)) {
        return true;
      }
    }
    return false;
  }

  /** {@inheritDoc} */
  Override
  public Object newSymbol(String tag) {
    for (int i = 0; i < actionTable.length; i++) {
      Object node = actionTable[i].newSymbol(tag);
      if (node != null) {
        setNodeAction(tag, actionTable[i]);
        return node;
      }
    }
    return null;
  }

  /**
   * {@inheritDoc}
   */
  Override
  public void setView(IlvSymbologyTreeView treeView) {
    super.setView(treeView);
    for (int i = 0; i < actionTable.length; i++) {
      actionTable[i].setView(treeView);
    }
  }

  /**
   * Returns the action attached to this tag.
   * 
   * @param tag
   *          symbol tag.
   * @return the action attached to this tag.
   */
  protected IlvSymbologyTreeViewActions getNodeAction(String tag) {
    return association.get(tag);
  }

  /**
   * Sets the action attached to this tag.
   * 
   * @param tag
   *          symbol tag.
   * @param action
   *          the action attached to this tag.
   */
  protected void setNodeAction(String tag, IlvSymbologyTreeViewActions action) {
    association.put(tag, action);
  }

  Override
  public IlvPersistentObject getPersistentContext() {
    IlvPersistentObject context[] = new IlvPersistentObject[actionTable.length];
    for (int i = 0; i < actionTable.length; i++) {
      context[i] = actionTable[i].getPersistentContext();
    }
    return new IlvTablePersistentContext(context);
  }

  Override
  public void setPersistentContext(IlvPersistentObject context) {
    if (context instanceof IlvTablePersistentContext) {
      IlvTablePersistentContext tableContext = (IlvTablePersistentContext) context;
      for (int i = 0; i < actionTable.length; i++) {
        if (tableContext.getContext()[i] != null) {
          actionTable[i].setPersistentContext(tableContext.getContext()[i]);
        }
      }
    }
  }

  Override
  public boolean isPropertyIgnored(IlvSDMModel model, Object node, String propertyName) {
    IlvSymbologyTreeViewActions actions = getNodeAction(model.getTag(node));
    if (actions != null) {
      return actions.isPropertyIgnored(model, node, propertyName);
    }
    return false;
  }

}