package cnp.ew.spin;
import cnp.ew.util.*;
import java.awt.*;
import java.util.*;
import cnp.ew.button.*;
import cnp.ew.image.*;
import cnp.ew.displayer.*;
import cnp.ew.lightweight.*;
import cnp.ew.layout.*;
import cnp.ew.properties.*;

public class CpSpinEditorLc extends CpAbstractLc implements CpEditor
{

    // list of fields
    Vector spinFields;

    // index of selected field
    int selectedFieldIndex;

    // true if shifting focus through the fields should wrap at the ends.
    boolean wrapAroundFields=true;

    // margin between fields
    static final int fieldMargin=2;

    CpLabeledImageButtonLc upButton, downButton;

    // the object we're editing
    Object model;

    static int downArrowId;
    static int upArrowId;

    static {
        downArrowId = CpToolkit.registerImageName("darrow5.gif");
        upArrowId = CpToolkit.registerImageName("uarrow5.gif");
    }


    public Object getModel()
    {
        return model;
    }

    // TBD: clean this interface up
    public Object getObject()
    {
        return null;
    }

    // TBD: Clean this interface up.
    public void setObject(Object object)
    {
    }



    public CpSpinEditorLc(String format)
    {
        super();

        CpAttachmentsLayout layout = new CpAttachmentsLayout();
        setLayout(layout);
        parseFormatString(format);
        setBorderStyle(BORDER_INWARD3D);
        setBackground(Color.white);
    }

    void parseFormatString(String formatString)
    {
        spinFields = new Vector(3);
        // TBD...
    }

    void addSpinField(CpSpinFieldLc field)
    {
        spinFields.addElement(field);
        field.setIsGroupStart(false);
        add(field);
    }

    /**
     * This must be called *after* all the spin fields are added; otherwise, the attachments
     * won't be set up properly.
     */
    void addButtons()
    {
        CpAttachments attachments;
        CpAttachmentsLayout layout = (CpAttachmentsLayout)getLayout();

        upButton = new CpLabeledImageButtonLc();
        upButton.setImage(
            CpToolkit.getImage(upArrowId),
            CpLabeledImageButtonLc.IMAGE_OUT
        );
        upButton.setUsesFocus(false);
        attachments = new CpAttachments();
        attachments.setRightAttachment(0);
        attachments.setTopAttachment(0);
        layout.setAttachments(upButton, attachments);
        add(upButton);
        upButton.addObserver(this);

        downButton = new CpLabeledImageButtonLc();
        downButton.setImage(
            CpToolkit.getImage(downArrowId),
            CpLabeledImageButtonLc.IMAGE_OUT
        );
        downButton.setUsesFocus(false);
        attachments = new CpAttachments();
        attachments.setRightAttachment(0);
        attachments.setTopAttachment(0, upButton);
        layout.setAttachments(downButton, attachments);
        add(downButton);
        downButton.addObserver(this);
        layoutSpinFields();
    }


    void layoutSpinFields()
    {
        CpAbstractLc previousField= null, curField;
        CpAttachments attachments;
        CpAttachmentsLayout layout = (CpAttachmentsLayout)getLayout();

        if (upButton != null) {
            previousField = upButton;
        }

        for (int i = spinFields.size() - 1; i >= 0; i--) {
            curField = (CpAbstractLc)spinFields.elementAt(i);
            attachments = new CpAttachments();
            if (previousField == null) {
                attachments.setRightAttachment(fieldMargin);
            } else {
                attachments.setRightAttachment(fieldMargin, previousField);
            }
            attachments.setVerticalCentering();
            if (i == 0) {
                attachments.setLeftAttachment(0);
            }
            layout.setAttachments(curField, attachments);
            previousField = curField;
        }
    }


    public void update(CpObservable o, int facet, Object arg)
    {
        if (o == upButton && facet == BUTTON_PRESSING) {
            incrementSelectedField();
            return;
        }

        if (o == downButton && facet == BUTTON_PRESSING) {
            decrementSelectedField();
            return;
        }
        if (o == model) {
            Enumeration e = spinFields.elements();
            while (e.hasMoreElements()) {
                ((CpSpinFieldLc)e.nextElement()).update(o, facet, arg);
            }
            Object obj = getObject();
            notifyObservers(OBJECT_CHANGING, obj);
            notifyObservers(OBJECT_CHANGED, obj);
        }
    }

    CpSpinFieldLc getSelectedField()
    {
        return (CpSpinFieldLc)spinFields.elementAt(selectedFieldIndex);
    }

    void setSelectedField(CpSpinFieldLc newField)
    {
        setSelectedFieldIndex(spinFields.indexOf(newField));
    }

    public void incrementSelectedField()
    {
        getSelectedField().increment();
    }

    public void decrementSelectedField()
    {
        getSelectedField().decrement();
    }

    public void setSelectedFieldIndex(int newIndex)
    {
        if (newIndex == selectedFieldIndex) { return; }
        getSelectedField().damage();
        selectedFieldIndex = newIndex;
        getSelectedField().requestFocus();
        getSelectedField().damage();
        repairDamage();
    }

    boolean keyCausesAdvance(int key)
    {
        if (selectedFieldIndex < spinFields.size() - 1) {
            CpSpinFieldLc fieldAfter = (CpSpinFieldLc)spinFields.elementAt(selectedFieldIndex + 1);
            if (fieldAfter instanceof CpStaticSpinFieldLc) {
                String text = ((CpStaticSpinFieldLc)fieldAfter).getText();
                return text.length() > 0 && text.charAt(0) == key;
            }
        }
        return false;
    }


    public boolean parentKeyDown(Event e, int key)
    {
        if (keyCausesAdvance(key)) {
            getSelectedField().shiftFocusForwardWithinGroup();
            return true;
        }

        switch (key) {
        case Event.UP:
        case '+':
            incrementSelectedField();
            return true;
        case Event.DOWN:
        case '-':
            decrementSelectedField();
            return true;
        }

        return false;
    }


    public void paint(Graphics g, Rectangle clipRect)
    {
        Rectangle bounds = bounds();
        g.setColor(getBackground());
        g.fillRect(0, 0, bounds.width, bounds.height);
    }

    // To Support CpEditor; we may add support for this later.
    public int getVerticalAlignment()
    {
        return ALIGN_TOP;
    }
    public void setVerticalAlignment(int verticalAlignment)
    {
    }
    public int getHorizontalAlignment()
    {
        return ALIGN_LEFT;
    }
    public void setHorizontalAlignment(int horizontalAlignment)
    {
    }

    public Dimension preferredSize()
    {
        int width=0, height=0;
        Dimension preferredSize;

        // if we're a spin field without buttons, these'll be null
        if (upButton != null) {
            preferredSize = upButton.preferredSize();
            height += preferredSize.height;
            width += preferredSize.width;

            preferredSize = downButton.preferredSize();
            height += preferredSize.height;
        }

        for (int i = 0; i < spinFields.size(); i++) {
            preferredSize = ((CpSpinFieldLc)spinFields.elementAt(i)).preferredSize();
            width += preferredSize.width;
            height = Math.max(preferredSize.height, height);
        }

        width += fieldMargin * spinFields.size();

        return borderedPreferredSize(new Dimension(width, height));
    }
/*
    public boolean usesFocus()
    {
        return true;
    }
*/

    /**
    * TBD: This should be in AbstractLc (didn't want to test thoroughly right now).  Remove
    * the test for usesFocus.
    */

    boolean basicWantsTabFocus()
    {
        return !isDisabled() && isTabStop();
    }

    public boolean gotFocus()
    {
        for (int i=0; i < spinFields.size(); i++) {
            CpLightweightComponent spinField = (CpLightweightComponent)spinFields.elementAt(i);
            if (spinField.usesFocus()) {
                spinField.requestFocus();
                return true;
            }
        }
        return true;
    }
}