/*
 * RowInfoMatcher.java
 *
 * Created on May 25, 2006, 12:52 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package usda.weru.util.diff.listbuilders;

import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import usda.weru.mcrew.Action;
import usda.weru.mcrew.OperationObject;
import usda.weru.mcrew.Parameter;
import usda.weru.util.diff.*;

/**
 *
 * @author Joseph Levin
 */
public class OperationObjectListBuilder extends ObjectListBuilder {

    /**
     *
     * @param engine
     * @param a
     * @param b
     * @return
     * @throws IncomparableObjectsException
     */
    @Override
    public DiffNode buildList(DiffEngine engine, Object a, Object b) throws IncomparableObjectsException {
        test(OperationObject.class, a, b);
        return applyExtras(buildList(engine, (OperationObject) a, (OperationObject) b));
    }

    /**
     *
     * @param engine
     * @param opA
     * @param opB
     * @return
     */
    public DiffNode buildList(DiffEngine engine, OperationObject opA, OperationObject opB) {
        DiffNode node = new DiffNode("Operation Object", opA, opB);

        if (opA != null) {
            node.setA(opA.getOperationName());
        }
        if (opB != null) {
            node.setB(opB.getOperationName());
        }

        if (opA == null || opB == null) {
            return node;
        }

        ActionWrapper rootActionA = buildActionTree(opA);
        ActionWrapper rootActionB = buildActionTree(opB);

        node.addChild(buildList(rootActionA, rootActionB));

        return node;
    }

    private DiffNode buildList(ActionWrapper wrapperA, ActionWrapper wrapperB) {
        DiffNode node = new DiffNode("Action Object", wrapperA, wrapperB);
        Action actionA = null;
        Action actionB = null;
        if (wrapperA != null) {
            actionA = wrapperA.getAction();
            if (actionA != null) {
                node.setA(actionA.getIdentity().toString() + " : " + actionA.getActionName());
            }
        }
        if (wrapperB != null) {
            actionB = wrapperB.getAction();
            if (actionB != null) {
                node.setB(actionB.getIdentity().toString() + " : " + actionB.getActionName());
            }
        }

        if (actionA == null || actionB == null) {
            return node;
        }

        //Add parameters
        for (Object o : actionA.getParameterNames()) {
            String parameter = (String) o;
            Parameter parameterA = actionA.getParameter(parameter);
            Parameter parameterB = actionB.getParameter(parameter);

            String valueA = null;
            String valueB = null;

            if (parameterA != null && parameterA.getValue() != null) {
                valueA = parameterA.getValue().toString();
            }
            if (parameterB != null && parameterB.getValue() != null) {
                valueB = parameterB.getValue().toString();
            }

            try {
                double dA = Double.parseDouble(valueA);
                double dB = Double.parseDouble(valueB);
                node.addChild(parameter, dA, dB);
            } catch (Exception e) {
                //Values are not numeric
                node.addChild(parameter, valueA, valueB);
            }
        }

        //Match the children
        Object[][] listA = matchList(wrapperA);
        Object[][] listB = matchList(wrapperB);
        Object[] matches = match(listA, listB, false, true);

        for (Object o : matches) {
            Object[] match = (Object[]) o;
            ActionWrapper childA = (ActionWrapper) match[0];
            ActionWrapper childB = (ActionWrapper) match[1];
            node.addChild(buildList(childA, childB));
        }
        return node;
    }

    private ActionWrapper buildActionTree(OperationObject op) {
        ActionWrapper root = null;
        ActionWrapper group = null;

        for (Object o : op.getAllActions()) {
            Action action = (Action) o;
            String code = action.getIdentity().code;
            if (code.equalsIgnoreCase("O")) {
                //Operation level.
                ActionWrapper wrapper = new ActionWrapper(action);
                root = wrapper;
            } else if (code.equalsIgnoreCase("G")) {
                //Group Level
                group = root.add(action);
            } else if (code.equalsIgnoreCase("P")) {
                //Process Level
                group.add(action);
            }
        }

        return root;
    }

    private Object[][] matchList(ActionWrapper wrapper) {

        Object temp[][] = new Object[wrapper.size()][2];
        for (int i = 0; i < wrapper.size(); i++) {
            Action action = wrapper.get(i).getAction();
            temp[i][0] = wrapper.get(i);
            temp[i][1] = action.getIdentity().toString();
        }
        return temp;
    }

    /**
     *
     */
    public class ActionWrapper implements Iterable<ActionWrapper> {

        private List<ActionWrapper> c_children;
        private Action c_action;

        /**
         *
         */
        public ActionWrapper() {
            c_children = new Vector<ActionWrapper>();
        }

        /**
         *
         * @param action
         */
        public ActionWrapper(Action action) {
            this();
            c_action = action;
        }

        /**
         *
         * @param action
         * @return
         */
        public ActionWrapper add(Action action) {
            ActionWrapper child = new ActionWrapper(action);
            c_children.add(child);
            return child;
        }

        /**
         *
         * @return
         */
        @Override
        public Iterator<ActionWrapper> iterator() {
            return c_children.iterator();
        }

        /**
         *
         * @return
         */
        public Action getAction() {
            return c_action;
        }

        /**
         *
         * @return
         */
        public int size() {
            return c_children.size();
        }

        /**
         *
         * @param index
         * @return
         */
        public ActionWrapper get(int index) {
            return c_children.get(index);
        }
    }

}
