package com.fitbank.schemautils;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.fitbank.serializador.xml.ExcepcionParser;
import com.fitbank.serializador.xml.ParserGeneral;

/**
 * Clase SchemaXML.
 * 
 * @author FitBank
 */
public class SchemaXML {
    /**
     * Parsea un String.
     * 
     * @param contenido
     *            String con el contenido
     * 
     * @return Un objeto Schema
     */
    public static Schema parseString(String contenido) throws ExcepcionParser {
        return parse(ParserGeneral.parseStringDoc(contenido));
    }

    /**
     * Parsea un uri.
     * 
     * @param uri
     *            URI a ser parseado
     * 
     * @return Un objeto Schema
     */
    public static Schema parse(String uri) throws ExcepcionParser,
            FileNotFoundException {
        return parse(ParserGeneral.parseDoc(uri));
    }

    /**
     * Parsea un uri.
     * 
     * @param uri
     *            URI a ser parseado
     * 
     * @return Un objeto Schema
     */
    public static Schema parse(InputStream is) throws ExcepcionParser {
        return parse(ParserGeneral.parse(is));
    }

    /**
     * Parsea un Document.
     * 
     * @param doc
     *            Document a ser parseado
     * 
     * @return Un objeto Schema
     * @throws ExcepcionParser
     * 
     * @throws Exception
     *             En caso de error
     */
    public static Schema parse(Document doc) throws ExcepcionParser {
        if (doc.getDocumentElement() == null) {
            throw new ExcepcionParser("Error al intentar obtener el "
                    + "Document de los campos consutables");
        }

        return generarDocumento(doc.getDocumentElement());
    }

    private static Schema generarDocumento(Element node) {
        Schema cc = new Schema();

        NodeList children = node.getChildNodes();

        if (children != null) {
            for (int i = 0; i < children.getLength(); i++) {
                if (children.item(i).getNodeType() == Node.ELEMENT_NODE) {
                    cc.addTable(generarTabla(children.item(i)));
                }
            }
        }

        return cc;
    }

    private static Table generarTabla(Node node) {
        Table table = new Table();
        NodeList attrs = node.getChildNodes();

        for (int i = 0; i < attrs.getLength(); i++) {
            if (attrs.item(i).getNodeType() == Node.ELEMENT_NODE
                    && attrs.item(i).getFirstChild() != null) {
                if (attrs.item(i).getNodeName().equalsIgnoreCase("tnum")) {
                    table.setCode(attrs.item(i).getFirstChild().getNodeValue());
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("tnom")) {
                    table.setName(attrs.item(i).getFirstChild().getNodeValue());
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("tdes")) {
                    table.setDescription(attrs.item(i).getFirstChild()
                            .getNodeValue());
                } else if (attrs.item(i).getNodeName()
                        .equalsIgnoreCase("campo")) {
                    table.addField(generarCampo(attrs.item(i)));
                }
            }
        }

        return table;
    }

    private static Field generarCampo(Node node) {
        Field field = new Field();
        NodeList attrs = node.getChildNodes();

        for (int i = 0; i < attrs.getLength(); i++) {
            if (attrs.item(i).getNodeType() == Node.ELEMENT_NODE) {
                if (attrs.item(i).getNodeName().equalsIgnoreCase("cnum")) {
                    field.setCode(attrs.item(i).getFirstChild().getNodeValue());
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("cnom")) {
                    field.setName(attrs.item(i).getFirstChild().getNodeValue());
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("cdes")) {
                    field.setDescription(attrs.item(i).getFirstChild()
                            .getNodeValue());
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("prim")) {
                    field.setPrimaryKey(StringUtils.trimToEmpty(
                            attrs.item(i).getFirstChild().getNodeValue())
                            .equals("1"));
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("tipd")) {
                    field.setType(attrs.item(i).getFirstChild().getNodeValue());
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("mand")) {
                    field.setRequired(StringUtils.trimToEmpty(
                            attrs.item(i).getFirstChild().getNodeValue())
                            .equals("1"));
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("defv")) {
                    field.setDefaultValue(attrs.item(i).getFirstChild()
                            .getNodeValue());
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("tpad")) {
                    field.getParentTables().addAll(
                            Arrays.asList(attrs.item(i).getFirstChild()
                                    .getNodeValue().split(Pattern.quote(","))));
                } else if (attrs.item(i).getNodeName().equalsIgnoreCase("hija")) {
                    field.getChildTables().addAll(
                            Arrays.asList(attrs.item(i).getFirstChild()
                                    .getNodeValue().split(Pattern.quote(","))));
                }
            }
        }

        return field;
    }
}
