
/*
 * Copyright (C) The Apache Software Foundation. All rights reserved.
 *
 * This software is published under the terms of the Apache Software License
 * version 1.1, a copy of which has been included with this distribution in
 * the LICENSE file.
 */
package org.apache.avalon.db.basic.handlers.lxsql;



import org.apache.avalon.db.server.AbstractRequestHandler;
import org.apache.avalon.db.basic.parser.BasicLXSQLParserManager;
import org.apache.avalon.db.basic.handlers.ContrivedColumnNameHolder;
import org.apache.avalon.db.services.DatabasePersistor;
import org.apache.avalon.db.actions.ActionException;
import org.apache.avalon.db.data.impl.AbstractQueryable;
import org.apache.avalon.db.data.impl.DefaultIntegerConstantColumn;
import org.apache.avalon.db.data.impl.DefaultStringConstantColumn;
import org.apache.avalon.db.data.impl.DefaultContrivedVarcharFunctionColumn;
import org.apache.avalon.db.data.impl.DefaultContrivedIntegerFunctionColumn;
import org.apache.avalon.db.data.impl.DefaultContrivedDateFunctionColumn;
import org.apache.avalon.db.data.impl.DefaultContrivedTimeFunctionColumn;
import org.apache.avalon.db.data.Column;
import org.apache.avalon.db.functions.impl.*;
//>>>>>>> 1.6
import org.apache.avalon.db.functions.StringFunction;
import org.apache.avalon.db.functions.NumericFunction;
import org.apache.avalon.db.functions.Function;
import org.apache.avalon.db.functions.TimeFunction;
import org.apache.avalon.db.functions.DateFunction;
import org.apache.avalon.db.functions.TimestampFunction;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.Vector;


/**
 * Class SelectColumnHelper
 *
 *
 * @author Paul Hammant <a href="mailto:Paul_Hammant@yahoo.com">Paul_Hammant@yahoo.com</a>
 * @version $Revision: 1.7 $
 */
public class SelectColumnHelper {


    protected boolean isAllColumns(Element elem) {
        String nodeName = elem.getNodeName();
        if (nodeName.equals("column")) {
            String name = elem.getAttribute("name");
            if (name.equals("*")) {
                return true;
            }
        }
        return false;
    }

    protected Column getSelectColumn(AbstractQueryable queryable, Element elem, ContrivedColumnNameHolder colHldr) throws ActionException {

        String nodeName = elem.getNodeName();

        if (nodeName.equals("column")) {
            return getSelectColumnColumn(queryable, elem);
        } else if (nodeName.equals("concat")) {
            return getColumnFromFunction(queryable, elem, new ConcatFunction(), colHldr);
        } else if (nodeName.equals("const")) {
            return getColumnConst(queryable, elem, colHldr);
        } else if (nodeName.equals("trim")) {
            if (elem.getAttribute("type").equals("leading")) {
                return getColumnFromFunction(queryable, elem, new LeadingTrimStringFunction(), colHldr);
            } else if (elem.getAttribute("type").equals("trailing")) {
                return getColumnFromFunction(queryable, elem, new TrailingTrimStringFunction(), colHldr);
            } else {
                return getColumnFromFunction(queryable, elem, new TrimStringFunction(), colHldr);
            }
        } else if (nodeName.equals("lowercase")) {
            return getColumnFromFunction(queryable, elem, new LowerCaseStringFunction(), colHldr);
        } else if (nodeName.equals("uppercase")) {
            return getColumnFromFunction(queryable, elem, new UpperCaseStringFunction(), colHldr);
        } else if (nodeName.equals("position")) {
            return getColumnFromFunction(queryable, elem, new PositionFunction(), colHldr);
        } else if (nodeName.equals("addition")) {
            return getColumnFromFunction(queryable, elem, new IntegerAdditionFunction(), colHldr);
        } else if (nodeName.equals("subtraction")) {
            return getColumnFromFunction(queryable, elem, new IntegerSubtractionFunction(), colHldr);
        } else if (nodeName.equals("multiplication")) {
            return getColumnFromFunction(queryable, elem, new IntegerMultiplicationFunction(), colHldr);
        } else if (nodeName.equals("division")) {
            return getColumnFromFunction(queryable, elem, new IntegerDivisionFunction(), colHldr);
        } else if (nodeName.equals("hourofday")) {
            return getColumnFromFunction(queryable, elem, new HourOfDayIntegerFunction(), colHldr);
        } else if (nodeName.equals("dayofmonth")) {
            return getColumnFromFunction(queryable, elem, new DayOfMonthIntegerFunction(), colHldr);
        } else if (nodeName.equals("minute")) {
            return getColumnFromFunction(queryable, elem, new MinuteIntegerFunction(), colHldr);
        } else if (nodeName.equals("month")) {
            return getColumnFromFunction(queryable, elem, new MonthIntegerFunction(), colHldr);
        } else if (nodeName.equals("dayname")) {
            return getColumnFromFunction(queryable, elem, new DayNameTemporalFunction(), colHldr);
        } else if (nodeName.equals("yearmonth")) {
            return getColumnFromFunction(queryable, elem, new YearMonthTemporalFunction(), colHldr);
        } else if (nodeName.equals("daysecond")) {
            return getColumnFromFunction(queryable, elem, new DayHourMinuteSecondTemporalFunction(), colHldr);
        } else if (nodeName.equals("hoursecond")) {
            return getColumnFromFunction(queryable, elem, new HourMinuteSecondTemporalFunction(), colHldr);
        } else if (nodeName.equals("hourminute")) {
            return getColumnFromFunction(queryable, elem, new HourMinuteTemporalFunction(), colHldr);
        } else if (nodeName.equals("minutesecond")) {
            return getColumnFromFunction(queryable, elem, new MinuteSecondTemporalFunction(), colHldr);
        } else if (nodeName.equals("second")) {
            return getColumnFromFunction(queryable, elem, new SecondIntegerFunction(), colHldr);
        } else if (nodeName.equals("year")) {
            return getColumnFromFunction(queryable, elem, new YearIntegerFunction(), colHldr);
        } else if (nodeName.equals("currentdate")) {
            return getColumnFromFunction(queryable, elem, new CurrentDateTemporalFunction(), colHldr);
        } else {
            throw new ActionException("Unknown node type '"+nodeName+"' under 'columns'");
        }
    }

    protected Column getSelectColumnColumn(AbstractQueryable queryable, Element elem) throws ActionException {
        String name = elem.getAttribute("name");
        return queryable.getColumn(name, true);
    }



    protected Column getColumnConst(AbstractQueryable queryable, Element aElem,
            ContrivedColumnNameHolder colHldr) throws ActionException {
        String value = aElem.getAttribute("value");
        String as = aElem.getAttribute("as");
        if (as.equals("")) {
            as = colHldr.getNextColumn();
        }
        // TODO more types
        try {
            return new DefaultIntegerConstantColumn(as,Integer.parseInt(value));
        } catch (java.lang.NumberFormatException nfe) {
            return new DefaultStringConstantColumn(as,value);
        }

    }

    protected Column getColumnFromFunction(AbstractQueryable queryable,
            Element aElem, Function function, ContrivedColumnNameHolder colHldr) throws ActionException {
        String as = aElem.getAttribute("as");
        if (as.equals("")) {
            as = colHldr.getNextColumn();
        }
        // TODO as might be missing
        //return queryable.getColumn(name, true);
        int count = 0;
        if (aElem.hasChildNodes() | function.getMinCols() > 0) {
            NodeList subConcatNodes = aElem.getChildNodes();
            Vector colVec = new Vector();
            for (int j=0; j < subConcatNodes.getLength(); j++) {
                Node node = subConcatNodes.item(j);

                String nodeName =  node.getNodeName();
                if (nodeName.equals("#text")) {
                    // do nothing
                } else {
                    count++;
                    colVec.add(getSelectColumn(queryable,(Element) node, colHldr));
                }
            }
            if (colVec.size() > function.getMaxCols() | colVec.size() < function.getMinCols() ) {
                throw new ActionException("Function "+aElem.getNodeName()+" can only have "+function.getMaxCols()+" child columns");
            }
            Column[] cols = new Column[colVec.size()];
            colVec.copyInto(cols);
            function.initialize(cols);
            return makeColumn(function, as);

        } else if (function.getMinCols() == 0) {
            //  no initialization needed.
            return makeColumn(function, as);
        } else {
            System.out.println("m m " + function.getMinCols() + " " + function.getMaxCols());
            throw new ActionException("Function "+aElem.getNodeName()+" must have child column");
        }
    }

    private Column makeColumn(Function function, String as) throws ActionException {
        if (function instanceof TimeFunction) {
            return new DefaultContrivedTimeFunctionColumn(as, (TimeFunction) function);
        } else if (function instanceof DateFunction) {
            return new DefaultContrivedDateFunctionColumn(as, (DateFunction) function);
        } else if (function instanceof TimestampFunction) {
            return new DefaultContrivedDateFunctionColumn(as, (DateFunction) function);
        } else if (function instanceof NumericFunction) {
            // TODO different types for 'preference'
            return new DefaultContrivedIntegerFunctionColumn(as, (NumericFunction) function);
        } else {
            return new DefaultContrivedVarcharFunctionColumn(as, (StringFunction) function);
        }
    }
}

