
/********************************************************************
 * Copyright © 2004 EDS. All rights reserved
 ********************************************************************/
package gov.vha.edb.rules.web.builder;

import ilog.rules.brl.*;
import ilog.rules.repository.brm.*;
import ilog.rules.repository.event.FeatureChangeEvent;
import ilog.rules.repository.model.*;
import ilog.rules.webui.*;
//import ilog.rules.dt.model.*;
//import ilog.rules.dt.model.IlrDTTableTreeModelWrapper;
import ilog.rules.dt.model.check.*;
import ilog.rules.dt.util.*;
//import ilog.rules.ui.dtable.*;
//import ilog.rules.util.prefs.*;
import ilog.webui.dhtml.IlxWComponent;
import ilog.webui.dhtml.IlxWPort;
import ilog.webui.dhtml.IlxWUtil;

import java.io.*;
import java.util.*;

public class BrmElementPanel extends ElementPanel implements IlrBrmConstants
{
  private static final long serialVersionUID = 1155107846879529437L;
  private TextView textView;
  private SyntacticView syntacticView;
  private DefinitionView currentView;
  private DecisionTableView mgrDTableView;
  private IlrProperty tokenModelProperty;

    public BrmElementPanel(WebBuilder builder)
    {
      super(builder);
    }

  protected IlrBrmElement getBrmElement()
  {
    return (IlrBrmElement) getElement();
  }

  public void setElement(IlrElement element)
  {
    super.setElement(element);

    if (element != null) {
      IlrRefPackage elementExtent = element.getExtent();
      IlrRefPackage metaRefPackage = ((IlrElement) elementExtent.refMetaObject()).getExtent();
      tokenModelProperty
          = (IlrProperty) metaRefPackage.findModelElement(IlrBrmConstants.TOKEN_MODEL_DEFINITION_CLASS
                                                          + "." + IlrBrmConstants.TOKEN_MODEL_PROPERTY);

      IlrBrmElement elt = (IlrBrmElement) element;
      IlrRefPackage refPack = builder.getCurrentExtent();

      IlrDefinition def = elt.getCurrentDefinition();

      if (def != null && def instanceof IlrTokenModelDefinition) {
        setSyntacticView((IlrTokenModelDefinition) def);
        builder.getDtableEditPanel().removeAll();
        builder.getDtableEditPanel().invalidate();

      } else if (def != null && def instanceof IlrDecisionTableDefinition) {

        setMgrDecisionTableView((IlrDecisionTableDefinition) def);

      } else {

        builder.getDtableEditPanel().removeAll();
        builder.getDtableEditPanel().invalidate();

        IlrElementClass defClass;
        def = null;
        IlrDeployer deployer = builder.getCurrentProject().getDeployer();
        deployer.setCurrentProject(builder.getCurrentProject());
        try {
          defClass
              = refPack.getElementClass(IlrBrmConstants.TRL_DEFINITION_CLASS);
          def = elt.getDefinition(defClass, deployer);
        } catch (Exception e) {
        }
        if (def == null) {
          try {
            defClass
                = refPack.getElementClass(IlrBrmConstants.IRL_DEFINITION_CLASS);
            def = elt.getDefinition(defClass, deployer);
          } catch (Exception e) {
          }
          if (def == null) {
            try {
              defClass
                  = refPack.getElementClass(IlrBrmConstants.CODE_DEFINITION_CLASS);
              def = elt.getDefinition(defClass, deployer);
            } catch (Exception e) {
            }
            if (def == null) {
              builder.getLogger().severe("Cannot find a definition for the given element");
              return;
            }
          }
          setTextView((IlrTextDefinition) def);
        } else {
          elt.setCurrentDefinition(def);
          setSyntacticView((IlrTokenModelDefinition) def);
        }

      }


    } else {
      DefinitionView oldView = currentView;
      if (oldView != null) {
        oldView.setDefinition(null);
      }
    }
  }

  public void featureChanged(FeatureChangeEvent event)
  {
    super.featureChanged(event);
    updateEditableStatus();
  }

  public void structureChanged(EventObject e)
  {
  }

  private void setTextView(IlrTextDefinition def)
  {
    DefinitionView oldView = currentView;
    if (oldView != null) {
      oldView.setDefinition(null);
    }
    currentView = getTextView();
    currentView.setDefinition(def);
    invalidate();
  }

  private void setSyntacticView(IlrTokenModelDefinition def)
  {
    DefinitionView oldView = currentView;
    if (oldView != null) {
      oldView.setDefinition(null);
    }
    currentView = getSyntacticView();
    currentView.setDefinition(def);
    invalidate();
  }

  private void setMgrDecisionTableView(IlrDecisionTableDefinition def)
  {
    DefinitionView oldView = currentView;
    if (oldView != null) {
      oldView.setDefinition(null);
    }

    currentView = getMgrDTableView();
    currentView.setDefinition(def);
    invalidate();
  }

  private TextView getTextView()
  {
    if (textView == null) {
      textView = new TextView();
      add(textView);
    }
    return textView;
  }

  private SyntacticView getSyntacticView()
  {
    if (syntacticView == null) {
      syntacticView = new SyntacticView();
      add(syntacticView);
    }
    return syntacticView;
  }

  private DecisionTableView getMgrDTableView()
  {
    if (mgrDTableView == null) {
      mgrDTableView = new DecisionTableView();
      add(mgrDTableView);
    }
    return mgrDTableView;
  }

  protected void printComponent(IlxWPort port) throws IOException
  {
    PrintWriter out = port.getWriter();
    boolean ie50 = port.getBrowserInfo().greaterOrEqualsIE50();
    if (ie50) {
      out.println("<div style=\"padding:5;height:100%\" nowrap>");
    }
    if (currentView != null) {
      currentView.print(port);
    }
    if (ie50) {
      out.println("</div>");
    }
  }

  public void updateEditableStatus()
  {
    if (currentView != null) {
      currentView.updateEditableStatus();
    }
  }

  abstract class DefinitionView extends IlxWComponent
  {
    protected IlrDefinition definition;

    public void setDefinition(IlrDefinition definition)
    {
      this.definition = definition;
    }

    public IlrDefinition getDefinition()
    {
      return this.definition;
    }

    public void updateEditableStatus()
    {
      // Do nothing by default.
    }

    public boolean canCheck()
    {
      return false;
    }

    public void check()
    {
    }
  }

  class TextView extends DefinitionView
  {

    private static final long serialVersionUID = -4682706482414924944L;
    
    private String text = null;

    public void setDefinition(IlrDefinition definition)
    {
      super.setDefinition(definition);
      if (definition != null) {
        this.text = ((IlrTextDefinition) definition).getText();
      } else {
        this.text = null;
      }
    }

    protected void printComponent(IlxWPort port) throws IOException
    {
      PrintWriter out = port.getWriter();
      if (text != null) {
        out.print("<code>");
        out.print(IlxWUtil.toHtml(text));
        out.println("</code>");
      }
    }
  }

  class SyntacticView extends DefinitionView
  {
    private static final long serialVersionUID = 5839098983601311943L;
    private IlrWSyntacticEditor syntacticEditor;

    public IlrWSyntacticEditor getSyntacticEditor()
    {
      if (syntacticEditor == null) {
        syntacticEditor = new IlrWSyntacticEditor();
        SyntacticView.this.add(syntacticEditor);
      }
      return syntacticEditor;
    }

    public void updateEditableStatus()
    {
      if (definition != null) {
        boolean editable = definition.acceptsModify(tokenModelProperty)
                			&& !definition.isFrozen();
        IlrWSyntacticEditor editor = getSyntacticEditor();
        if (editor.isEditable() != editable) {
          editor.setEditable(editable);
        }
      }
    }

    public void setDefinition(IlrDefinition definition)
    {
      super.setDefinition(definition);
      IlrWSyntacticEditor editor = getSyntacticEditor();
      if (definition != null) {
        if (editor.getTokenModel() != null) {
          editor.clearTokenStyles("error");
        }

        IlrTokenModel model
            = ((IlrTokenModelDefinition) definition).getTokenModel();
        model.removeTokenModelListener(tokenModelListener);
        model.addTokenModelListener(tokenModelListener);
        model.setLocale(getBuilder().getLocale());
        editor.setTokenModel(model);
        updateEditableStatus();
      } else {
        IlrTokenModel oldModel = editor.getTokenModel();
        if (oldModel != null) {
          oldModel.removeTokenModelListener(tokenModelListener);
          editor.setTokenModel(null);
        }
      }
    }

    protected void printComponent(IlxWPort port) throws IOException
    {
      getSyntacticEditor().print(port);
    }

    private class PanelTokenModelListener
        implements TokenModelListener, Serializable
    {
      private static final long serialVersionUID = -5502059187965761964L;

    private void update()
      {
        IlrTokenModelDefinition def
            = (IlrTokenModelDefinition) getDefinition();
        if (def instanceof IlrTokenModelDefinition) {
          def.valueModified(tokenModelProperty);
          def.setModified(true);
          getSyntacticEditor().clearTokenStyles("error");
          final WebBuilder builder = getBuilder();
          // Update the menu after the action has been completely
          // performed on the token model; otherwise the canUndo/canRedo
          // will not take the change into account.
          IlxWPort port = IlxWPort.getCurrentPort();
          if (port != null) {
            port.invokeLater(new Runnable()
            {
              public void run()
              {
                builder.updateActionState(builder
                                          .getWebAction(BuilderActions
                                                        .ACTION_UNDO));
                builder.updateActionState(builder
                                          .getWebAction(BuilderActions
                                                        .ACTION_REDO));
              }
            });
          }
        }
      }

      public void tokenChanged(TokenChangedEvent e)
      {
        update();
      }

      public void tokenAdded(TokenAddedEvent e)
      {
        update();
      }

      public void tokenRemoved(TokenRemovedEvent e)
      {
        update();
      }
    }

    private TokenModelListener tokenModelListener
        = new PanelTokenModelListener();

    public boolean canCheck()
    {
      return true;
    }

    public void check()
    {
      IlrTokenModel model = getSyntacticEditor().getTokenModel();
      IlrTokenModelChecker checker = model.makeChecker();
      getSyntacticEditor().clearTokenStyles("error");
      if (checker != null) {
        IlrTokenError[] errors = checker.checkTokenModel();
        String name = ((IlrModelElement) getElement()).getName();
        WebBuilder builder = getBuilder();
        if (errors != null) {
          int length = errors.length;
          if (length > 0) {
            String msg = builder.getMessage("Messages.RuleHasErrors",
                                            name);
            builder.addMessage(msg);
            Vector tokens = new Vector();
            for (int i = 0; i < errors.length; i++) {
              IlrToken.Token token = errors[i].getToken();
              msg = builder.getMessage("Messages.TokenError",
                                       i + "");
              msg = "  " + msg + " " + errors[i].getMessage();
              tokens.addElement(token);
              builder.addMessage(msg);
            }
            getSyntacticEditor().addTokenStyle(tokens, "error");
          }
        } else {
          String msg = builder.getMessage("Messages.RuleIsCorrect",
                                          name);
          builder.addMessage(msg);
        }
      }
    }
  }

  class DecisionTableView extends DefinitionView
  {
    private static final long serialVersionUID = 7400267771530370037L;
    private IlrDTWTableView tableView;
    private transient Properties preferenceProperties;
    private transient ResourceBundle messagesBundle;
    private transient ResourceBundle preferencesBundle;
    private boolean firstCall = true;

    public IlrDTWTableView getDecisionTable()
    {
      return tableView;
    }

    public IlrTokenModel getTokenModel()
    {
      return null;
    }

    public void setDefinition(IlrDefinition definition)
    {
      super.setDefinition(definition);

      if (firstCall) {

        setupResources();


        IlrDecisionTableDefinition def = (IlrDecisionTableDefinition) getDefinition();
        tableView = new IlrDTWTableView(builder.getDtableEditPanel(), def);

        DecisionTableView.this.add(tableView);

        firstCall = false;

      }

      IlrDecisionTableDefinition def = (IlrDecisionTableDefinition) getDefinition();

      if (def != null) {

        if (tableView != null) {
          tableView.removeAll();
          DecisionTableView.this.remove(tableView);
        }

        tableView = new IlrDTWTableView(builder.getDtableEditPanel(), def);

        DecisionTableView.this.add(tableView);

      } else {

        DecisionTableView.this.remove(tableView);

      }
    }

    private void setupResources() {

      try {
        messagesBundle = ResourceBundle.getBundle("gov.vha.edb.rules.web.builder.dtable_messages",
                                                  builder.getLocale(),
                                                  WebBuilder.class.getClassLoader());
        preferencesBundle = ResourceBundle.getBundle("gov.vha.edb.rules.web.builder.dtable_preferences",
                                                     builder.getLocale(),
                                                     WebBuilder.class.getClassLoader());

      } catch (MissingResourceException e) {
        IlxWUtil.debugTrace("COULDN'T FIND RESSOURCES");
        e.printStackTrace();
      }

      preferenceProperties = new Properties();
      try {
        String builderProps = "/gov/vha/edb/rules/web/builder/dtable_preferences.properties";
        InputStream stream
            = WebBuilder.class.getResourceAsStream(builderProps);
        preferenceProperties.load(stream);
      } catch (IOException e) {
        IlxWUtil.debugTrace("COULDN'T FIND PROPERTIES");
        e.printStackTrace();
      }

      // TODO: Put this in IlrDTWTableView support.
      IlrDTUtil.setSingleton(new WebDtUtil(messagesBundle, preferenceProperties));
    }

    protected void printComponent(IlxWPort port) throws IOException
    {
      IlrDTWTableView wtableView = getDecisionTable();
      wtableView.print(port);
    }

    public boolean canCheck()
    {
      return true;
    }

    public void check()
    {
      IlrDecisionTableDefinition def = (IlrDecisionTableDefinition) getDefinition();
      List errors = IlrDTCheckerManager.getErrors(def.getDTModel());
      String name = ((IlrModelElement) getElement()).getName();

      if(errors != null && errors.size() > 0) {
        String msg = builder.getMessage("Messages.RuleHasErrors",
                                        name);
        builder.addMessage(msg);

        for (int i=0; i<errors.size(); i++) {

          msg = builder.getMessage("Messages.TokenError",
                                   i + "");
          msg = "  " + msg + " " + errors.get(i).toString();
          builder.addMessage(msg);

        }
      } else {
        builder.addMessage(builder.getMessage("Messages.RuleIsCorrect", name));
      }
    }

  }

  public void undo()
  {
    IlrWSyntacticEditor editor = getSyntacticEditorOrNull();
    if (editor != null) {
      editor.undo();
    }
  }

  public void redo()
  {
    IlrWSyntacticEditor editor = getSyntacticEditorOrNull();
    if (editor != null) {
      editor.redo();
    }
  }

  public void check()
  {
    currentView.check();
  }

  public boolean canUndo()
  {
    IlrWSyntacticEditor editor = getSyntacticEditorOrNull();
    if (editor != null) {
      return editor.canUndo();
    }
    return super.canUndo();
  }

  public boolean canRedo()
  {
    IlrWSyntacticEditor editor = getSyntacticEditorOrNull();
    if (editor != null) {
      return editor.canRedo();
    }
    return super.canRedo();
  }

  public boolean canCheck()
  {
    return currentView != null && currentView.canCheck(); // (getSyntacticEditorOrNull() != null);
  }

  private IlrWSyntacticEditor getSyntacticEditorOrNull()
  {
    if (currentView != null && currentView instanceof SyntacticView) {
      return ((SyntacticView) currentView).getSyntacticEditor();
    }
    return null;
  }

  private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException
  {
    if (currentView instanceof DecisionTableView)
      ((DecisionTableView)currentView).setupResources();
  }

}
