/*
 * Copyright 2012 s_wolff.
 *
 * 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.
 */
package org.aegee.runanddine.util.forms;

import java.io.Serializable;

import org.aegee.runanddine.util.forms.behaviours.CssErrorClassAdder;
import org.aegee.runanddine.util.forms.behaviours.CssErrorClassRemover;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;

/**
 * Class for displaying two text fields side by side.
 *
 * @author s_wolff
 */
public class DoubleTextField<T extends Serializable> extends Panel implements Serializable {

    public static final int GRID_WIDTH_20 = 20;
    public static final int GRID_WIDTH_25 = 25;
    public static final int GRID_WIDTH_33 = 33;
    public static final int GRID_WIDTH_38 = 38;
    public static final int GRID_WIDTH_40 = 40;
    public static final int GRID_WIDTH_50 = 50;
    public static final int GRID_WIDTH_60 = 60;
    public static final int GRID_WIDTH_62 = 62;
    public static final int GRID_WIDTH_66 = 66;
    public static final int GRID_WIDTH_75 = 75;
    public static final int GRID_WIDTH_80 = 80;
    private static final String ID_WRAPPER = "wrapper";
    private static final String ID_FEEDBACK = "feedback";
    private static final String ID_LABEL = "label";
    private static final String ID_LEFT_WRAPPER = "input1Wrapper";
    private static final String ID_RIGHT_WRAPPER = "input2Wrapper";
    private static final String ID_LEFT_INPUT = "input1";
    private static final String ID_RIGHT_INPUT = "input2";
    private static final String REQUIRED = "<sup class=\"ym-required\">*</sup>";
    private WebMarkupContainer wrapper;
    private WebMarkupContainer wrapperLeft, wrapperRight;
    private SuperDuperFeedbackPanel feedback;
    private Label label;
    private FormComponent inputLeft, inputRight;
    private int dominantInput = -1; // == 1 for inputLeft; == 2 for inputRight

    /**
     * Create a double text field. A validator is added to each input field
     * automatically to ensure that the provided input can be saved in the given
     * object after the form was sumitted successfully.
     *
     * @param id the component markup id
     * @param obj the object that backens the form field
     * @param fieldNameLeft the field name of the object that backens the left
     * input field
     * @param fieldNameRight the field name of the object that backens the right
     * input field
     * @param labelText the label text that shall be displayed for this field
     * @param required whether this field is required or optional
     * @param widthLeft the width in percent of the left input field
     * @param widthRight the width in percent of the right input field
     */
    public DoubleTextField(String id, T obj, String fieldNameLeft, String fieldNameRight, String labelText, boolean required, int widthLeft, int widthRight) {
        super(id);

        this.inputLeft = new org.apache.wicket.markup.html.form.TextField(ID_LEFT_INPUT, TextField.getFieldType(obj, fieldNameLeft));
        this.inputRight = new org.apache.wicket.markup.html.form.TextField(ID_RIGHT_INPUT, TextField.getFieldType(obj, fieldNameRight));

        this.init(obj, fieldNameLeft, fieldNameRight, labelText, required, widthLeft, widthRight);
    }

    private void init(T obj, String fieldNameLeft, String fieldNameRight, String labelText, boolean required, int widthLeft, int widthRight) {
        this.wrapper = new WebMarkupContainer(ID_WRAPPER);
        this.wrapperLeft = new WebMarkupContainer(ID_LEFT_WRAPPER);
        this.wrapperRight = new WebMarkupContainer(ID_RIGHT_WRAPPER);

        this.wrapperLeft.add(new CssGridAdder(widthLeft));
        this.wrapperRight.add(new CssGridAdder(widthRight));
        this.dominantInput = widthLeft >= widthRight ? 1 : 2;

        super.add(this.wrapper);
        this.wrapper.add(this.wrapperLeft, this.wrapperRight);

        // init inputs
        this.wrapperLeft.add(initInput(obj, this.inputLeft, fieldNameLeft, required));
        this.wrapperRight.add(initInput(obj, this.inputRight, fieldNameRight, required));

        this.initLabel(labelText, required);
        this.initFeedbackLabel();
    }

    private void initFeedbackLabel() {
        assert this.inputLeft != null && this.inputRight != null;
        this.feedback = new SuperDuperFeedbackPanel(ID_FEEDBACK, this.inputLeft, this.inputRight);
        this.wrapper.add(this.feedback);
    }

    private void initLabel(String labelText, boolean required) {
        assert this.inputLeft != null && this.inputRight != null && this.dominantInput != -1;
        this.label = new Label(ID_LABEL, generateLabelText(labelText, required));
        this.label.setEscapeModelStrings(false);
        String forInput = this.dominantInput == 1 ? this.inputLeft.getMarkupId() : this.inputRight.getMarkupId();
        this.label.add(new SimpleAttributeModifier("for", forInput));
        this.wrapper.add(this.label);
    }

    private FormComponent initInput(T obj, FormComponent comp, String fieldName, boolean required) {
        comp.setRequired(required);
        comp.setMarkupId(fieldName);
        comp.setModel(new PropertyModel<T>(obj, fieldName));
        return comp;
    }

    private static String generateLabelText(String labelText, boolean required) {
        return labelText + (required ? REQUIRED : "");
    }

    /**
     * Adds a behaviour modifier to the left input component.
     *
     * @param behaviours the behaviour modifiers that shall be added
     * @return
     * <code>this</code>
     */
    public DoubleTextField<T> addLeftInputBehaviour(Behavior... behaviours) {
        this.inputLeft.add(behaviours);
        return this;
    }

    /**
     * Adds a behaviour modifier to the right input component.
     *
     * @param behaviours the behaviour modifiers that shall be added
     * @return
     * <code>this</code>
     */
    public DoubleTextField<T> addRightInputBehaviour(Behavior... behaviours) {
        this.inputRight.add(behaviours);
        return this;
    }

    @Override
    protected void onBeforeRender() {
        super.onBeforeRender();
        if (this.feedback.anyMessage()) {
            this.wrapper.add(new CssErrorClassAdder());
        } else {
            this.wrapper.add(new CssErrorClassRemover(wrapper));
        }
    }

    /**
     * <code>AttributeAppender</code> shortcut for setting yaml grid widths.
     */
    private class CssGridAdder extends AttributeAppender {

        public CssGridAdder(int width) {
            super("class", true, new Model<String>("ym-g" + width), " ");
        }
    }
}
