package org.apache.cocoon.woody.datatype;

import java.util.Iterator;
import java.util.Locale;

import org.apache.avalon.framework.context.Context;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.components.flow.FlowHelper;
import org.apache.cocoon.woody.Constants;
import org.apache.cocoon.xml.AttributesImpl;
import org.apache.cocoon.transformation.I18nTransformer;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.Pointer;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

/**
 * <p>Zanibal Enterprise Suite</p>
 * <p>Copyright: Copyright (c) 2003</p>
 * Company: Zanibal LLC</p>
 * @author UIgwebuike
 * @version 1.0
 */
public class FlowJXPathSelectionListWPrompt implements SelectionList {

    private Context context;
    private String listPath;
    private String valuePath;
    private String labelPath;
    private String msgKey;
    private Datatype datatype;
    private Object model;

    public FlowJXPathSelectionListWPrompt(Context context, String listPath, String valuePath, String labelPath,
                                          String msgKey, Datatype datatype) {
        this.context = context;
        this.listPath = listPath;
        this.valuePath = valuePath;
        this.labelPath = labelPath;
        this.datatype = datatype;
        this.msgKey = msgKey;
    }

    /**
     * Builds a dynamic selection list from an in-memory collection.
     * @see org.apache.cocoon.woody.formmodel.Field#setSelectionList(Object model, String valuePath, String labelPath)
     * @param model The collection used as a model for the selection list.
     * @param valuePath An XPath expression referring to the attribute used
     * to populate the values of the list's items.
     * @param labelPath An XPath expression referring to the attribute used
     * to populate the labels of the list's items.
     * @param datatype
     */
    public FlowJXPathSelectionListWPrompt(Object model, String valuePath, String labelPath, Datatype datatype) {
        this.model = model;
        this.valuePath = valuePath;
        this.labelPath = labelPath;
        this.datatype = datatype;
    }

    public Datatype getDatatype() {
        return this.datatype;
    }

    public void generateSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException {

        JXPathContext ctx = null;
        Iterator iter = null;
        if (model == null) {
            Object flowData = FlowHelper.getContextObject(ContextHelper.getObjectModel(this.context));

            if (flowData == null) {
                throw new SAXException("No flow data to produce selection list");
            }
            // Move to the list location
            ctx = JXPathContext.newContext(flowData);

            // Iterate on all elements of the list
            iter = ctx.iteratePointers(this.listPath);
        } else {
            // Move to the list location
            ctx = JXPathContext.newContext(model);

            // Iterate on all elements of the list
            iter = ctx.iteratePointers(".");
        }


        // Start the selection-list
        contentHandler.startElement(Constants.WI_NS, SELECTION_LIST_EL, Constants.WI_PREFIX_COLON + SELECTION_LIST_EL, Constants.EMPTY_ATTRS);

        AttributesImpl itemAttrs = new AttributesImpl();

        //Add an i18n prompt message

        // Start wi:material
        itemAttrs.addCDATAAttribute("value", "");
        contentHandler.startElement(Constants.WI_NS, ITEM_EL, Constants.WI_PREFIX_COLON + ITEM_EL, itemAttrs);

        // Start wi:label
        contentHandler.startElement(Constants.WI_NS, LABEL_EL, Constants.WI_PREFIX_COLON + LABEL_EL, Constants.EMPTY_ATTRS);

        if (this.msgKey != null) {

            contentHandler.startPrefixMapping("i18n", I18nTransformer.I18N_NAMESPACE_URI);

            contentHandler.startElement(I18nTransformer.I18N_NAMESPACE_URI, I18nTransformer.I18N_TEXT_ELEMENT, "i18n:" + I18nTransformer.I18N_TEXT_ELEMENT, Constants.EMPTY_ATTRS);
            contentHandler.characters(this.msgKey.toCharArray(), 0, this.msgKey.length());
            contentHandler.endElement(I18nTransformer.I18N_NAMESPACE_URI, I18nTransformer.I18N_TEXT_ELEMENT, "i18n:" + I18nTransformer.I18N_TEXT_ELEMENT);

            contentHandler.endPrefixMapping("i18n");

        }

        // End wi:label
        contentHandler.endElement(Constants.WI_NS, LABEL_EL, Constants.WI_PREFIX_COLON + LABEL_EL);

        // End wi:material
        contentHandler.endElement(Constants.WI_NS, ITEM_EL, Constants.WI_PREFIX_COLON + ITEM_EL);

        //End of adding an i18n prompt message

        //Process the rest of the list
        while (iter.hasNext()) {

            String stringValue = "";
            String stringLabel = null;
            // Get a context on the current material
            Pointer ptr = (Pointer) iter.next();
            if (ptr.getValue() != null) {
                JXPathContext itemCtx = ctx.getRelativeContext(ptr);

                // Get the value as a string
                Object value = itemCtx.getValue(this.valuePath);
                stringValue = this.datatype.convertToString(value, locale);

                // Get the label (can be ommitted)
                itemCtx.setLenient(true);
                Object label = itemCtx.getValue(this.labelPath);
                stringLabel = (label == null) ? stringValue : label.toString();
            }

            // Output this material
            itemAttrs = new AttributesImpl();
            itemAttrs.addCDATAAttribute("value", stringValue);
            contentHandler.startElement(Constants.WI_NS, ITEM_EL, Constants.WI_PREFIX_COLON + ITEM_EL, itemAttrs);
            if (stringLabel != null) {
                contentHandler.startElement(Constants.WI_NS, LABEL_EL, Constants.WI_PREFIX_COLON + LABEL_EL, Constants.EMPTY_ATTRS);
                contentHandler.characters(stringLabel.toCharArray(), 0, stringLabel.length());
                contentHandler.endElement(Constants.WI_NS, LABEL_EL, Constants.WI_PREFIX_COLON + LABEL_EL);
            }
            contentHandler.endElement(Constants.WI_NS, ITEM_EL, Constants.WI_PREFIX_COLON + ITEM_EL);
        }

        // End the selection-list
        contentHandler.endElement(Constants.WI_NS, SELECTION_LIST_EL, Constants.WI_PREFIX_COLON + SELECTION_LIST_EL);
    }
}


