/**
 *    Copyright 2011 Peter Murray-Rust et. al.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

// /*======AUTOGENERATED FROM SCHEMA; DO NOT EDIT BELOW THIS LINE ======*/
package org.xmlcml.cml.element;

import java.util.ArrayList;
import java.util.List;

import nu.xom.Element;
import nu.xom.Node;

import org.xmlcml.cml.base.CMLConstants;
import org.xmlcml.cml.base.CMLElement;
import org.xmlcml.cml.base.CMLElements;
import org.xmlcml.cml.base.CMLUtil;
import org.xmlcml.cml.interfacex.HasArraySize;

/** A list of arrays or lists.
*
*
* \n A major use of arrayList is to contain data within rectangular tables. However there is no \nabsolute requirement and the table can have any shape. The shape attribute hould be used \nto assert rectangularity. \n\n
*
* user-modifiable class autogenerated from schema if no class exists
* use as a shell which can be edited
* the autogeneration software will not overwrite an existing class file

*/
public class CMLArrayList extends org.xmlcml.cml.element.AbstractArrayList {

    /** must give simple documentation.
    *

    */

    public CMLArrayList() {
    }
    /** must give simple documentation.
    *
    * @param old CMLArrayList to copy

    */

    public CMLArrayList(CMLArrayList old) {
        super((org.xmlcml.cml.element.AbstractArrayList) old);
    }

    /** copy node .
    *
    * @return Node
    */
    public Element copy() {
        return new CMLArrayList(this);
    }
    /** create new instance in context of parent, overridable by subclasses.
    *
    * @param parent parent of element to be constructed (ignored by default)
    * @return CMLArrayList
    */
    public CMLElement makeElementInContext(Element parent) {
        return new CMLArrayList();
    }

    /** create tableHeader from chidren.
     * @throws RuntimeException if chidren are inconsistent
     * @return tableHeader (may be empty)
     */
    public CMLTableHeader createTableHeader() {
        CMLTableHeader tableHeader = new CMLTableHeader();
//        CMLUtil.throwNYI();
        List<HasArraySize> arraysAndLists = this.getArrays();
        for (HasArraySize node : arraysAndLists) {
            CMLTableHeaderCell tableHeaderCell = this.createTableHeaderCell(node);
            tableHeader.addTableHeaderCell(tableHeaderCell);
        }
        return tableHeader;
    }

    /** create tableHeaderCell by copying attributes from array or list.
     * new cell has no string content.
     * @param node array or list
     * @return cell (never null)
     */
    public CMLTableHeaderCell createTableHeaderCell(HasArraySize node) {
        CMLTableHeaderCell tableHeaderCell = null;
        if (node instanceof CMLArray) {
            tableHeaderCell = createTableHeaderCell((CMLArray) node);
        } else if (node instanceof CMLList) {
            tableHeaderCell = createTableHeaderCell((CMLList) node);
        }
        return tableHeaderCell;
    }

    /** create tableHeaderCell by copying attributes from array.
     * new cell has no string content.
     * @param array
     * @return cell (never null)
     */
    public CMLTableHeaderCell createTableHeaderCell(CMLArray array) {
        CMLTableHeaderCell tableHeaderCell = new CMLTableHeaderCell();
        if (array.getTitleAttribute() != null) {
            tableHeaderCell.setTitle(array.getTitle());
        }
        if (array.getIdAttribute() != null) {
            tableHeaderCell.setId(array.getId());
        }
        if (array.getDictRefAttribute() != null) {
            tableHeaderCell.setDictRef(array.getDictRef());
        }
        if (array.getConventionAttribute() != null) {
            tableHeaderCell.setConvention(array.getConvention());
        }
        if (array.getConstantToSIAttribute() != null) {
            tableHeaderCell.setConstantToSI(array.getConstantToSI());
        }
        if (array.getMultiplierToSIAttribute() != null) {
            tableHeaderCell.setMultiplierToSI(array.getMultiplierToSI());
        }
        if (array.getDataTypeAttribute() != null) {
            tableHeaderCell.setDataType(array.getDataType());
        }
        if (array.getUnitTypeAttribute() != null) {
            tableHeaderCell.setUnitType(array.getUnitType());
        }
        if (array.getUnitsAttribute() != null) {
            tableHeaderCell.setUnits(array.getUnits());
        }
        return tableHeaderCell;
    }

    /** create tableHeaderCell by copying attributes from list.
     * new cell has no string content.
     * @param list
     * @return cell (never null)
     */
    public CMLTableHeaderCell createTableHeaderCell(CMLList list) {
        CMLTableHeaderCell tableHeaderCell = new CMLTableHeaderCell();
        if (list.getTitleAttribute() != null) {
            tableHeaderCell.setTitle(list.getTitle());
        }
        if (list.getIdAttribute() != null) {
            tableHeaderCell.setId(list.getId());
        }
        if (list.getDictRefAttribute() != null) {
            tableHeaderCell.setDictRef(list.getDictRef());
        }
        if (list.getConventionAttribute() != null) {
            tableHeaderCell.setConvention(list.getConvention());
        }
        List<Node> childNodes = CMLUtil.getQueryNodes(this, CMLConstants.S_STAR);
        if (childNodes.size() > 0) {
            tableHeaderCell.setDataType(((Element)childNodes.get(0)).getQualifiedName());
        }
        return tableHeaderCell;
    }

    /** get ordered list of array and list children.
     *
     * @return list (may be empty)
     */
    public List<HasArraySize> getArrays() {
        List<HasArraySize> list = new ArrayList<HasArraySize>();
        List<Node> nodes = CMLUtil.getQueryNodes(this,
                CMLArray.NS+X_OR+CMLList.NS, CMLConstants.CML_XPATH);
        for (Node node : nodes) {
            list.add((HasArraySize) node);
        }
        return list;
    }

    /** get count of array and list children.
     *
     * @return count
     */
    public int getArraysCount() {
        return this.getArrays().size();
    }

    /** create tableContent.
     *
     * @return tableContent
     */
    public CMLTableContent createTableContent() {
        String delimiter = this.getCommonDelimiter();
        CMLTableContent tableContent = new CMLTableContent();
        if (delimiter != null) {
            tableContent.setDelimiter(delimiter);
        }
        List<HasArraySize> listsAndArrays = this.getArrays();
        int nCol = listsAndArrays.size();
        if (nCol > 0) {
            int rowCount = ((HasArraySize)listsAndArrays.get(0)).getArraySize();
            List<List<String>> stringLists = new ArrayList<List<String>>();
            for (HasArraySize node : listsAndArrays) {
                stringLists.add(((HasArraySize)node).getStringValues());
            }
            for (int iRow = 0; iRow < rowCount; iRow++) {
                for (int jCol = 0; jCol < nCol; jCol++) {
                    String s = stringLists.get(jCol).get(iRow);
                    tableContent.append(s, delimiter);
                }
            }
            tableContent.finishAppendingStrings(delimiter);
        }
        return tableContent;
    }

    /** iterate through children to see if all delimiters are identical.
     * @throws RuntimeException if inconsistent
     * @return common delimiter
     */
    public String getCommonDelimiter() {
        String delimiter = null;
        CMLElements<CMLArray> arrays = this.getArrayElements();
        for (CMLArray array : arrays) {
            String delimiter0 = array.getDelimiter();
            if (delimiter == null) {
                if (delimiter0 != null) {
                    delimiter = delimiter0;
                }
            } else {
                if (!delimiter0.equals(delimiter)) {
                    throw new RuntimeException("Cannot find common delimiter: >"
                        +delimiter0+"::"+delimiter +"<");
                }
            }
        }
        return delimiter;
    }

    /** get row size (from first array).
     *
     * @return size
     */
    public int getRowCount() {
        int rows = 0;
        if (this.getArraysCount() > 0) {
            HasArraySize array = (HasArraySize) this.getArrays().get(0);
            rows = array.getArraySize();
        }
        return rows;
    }

}
