/*
 * Copyright 2010, Nimble Storage, Inc.
 */
package com.nimblestorage.nimbus.client.widgets.product.manage.initiator.initiatorgroup;

import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Timer;
import com.nimblestorage.nimbus.client.widgets.product.manage.initiator.initiatorgroup.TstTooltipFactory.AbstractValidationWrapper;
import com.nimblestorage.nimbus.client.widgets.product.manage.initiator.initiatorgroup.TstTooltipFactory.IValidationComponent;
import com.smartgwt.client.core.Rectangle;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import com.smartgwt.client.widgets.form.validator.RegExpValidator;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;

public class TstErrWindow extends Window {

    private VLayout mBodyHLayout;
    protected HLayout initiatorsListAddRemovePanel = new HLayout();
    private final HLayout mButtonsHLayout = new HLayout();
    private IButton mOkButton;
    private final TextBoxWithTooltipError initiatorNamePanel = new TextBoxWithTooltipError();
    private final TextBoxWithTooltipError initiatorIPPanel = new TextBoxWithTooltipError();
    private final TextBoxWithTooltipError initiatorIQNPanel = new TextBoxWithTooltipError();

    private final ButtonClickHandler mButtonClickHandler = new ButtonClickHandler();
    private static final String sVALID_NAME_PATTERN = "^[0-9a-zA-Z][0-9a-zA-Z\\-\\.:]{0,63}$";
    public static final RegExpValidator NameValidator = new RegExpValidator(
            sVALID_NAME_PATTERN);
    public static final String IP_BYTE_PATTERN = "(([01]?[0-9]?[0-9])|(2(([0-4][0-9])|(5[0-5]))))";
    private static final String sIP_PATTERN = IP_BYTE_PATTERN + "\\."
            + IP_BYTE_PATTERN + "\\." + IP_BYTE_PATTERN + "\\."
            + IP_BYTE_PATTERN;
    private static final String sSINGLE_IP_PATTERN = "^\\s*" + sIP_PATTERN
            + "\\s*$";
    public static final RegExpValidator SingleIpAddressValidator = new RegExpValidator(
            sSINGLE_IP_PATTERN);
    private static final String sINITIATOR_NAME_PATTERN = "^[^\\-\\.\\:][0-9a-zA-Z\\-\\.\\:]+$";
    public static final RegExpValidator InitiatorNameValidator = new RegExpValidator(
            sINITIATOR_NAME_PATTERN);

    protected TstErrWindow() {
        initializeWidgets();
        formatWidgets();
        organizeWidgets();
    }

    protected void initializeWidgets() {
        // TstTooltipFactory.setChildLayout(this);
        mBodyHLayout = new VLayout();
        mOkButton = new IButton("ok");
        mOkButton.addClickHandler(mButtonClickHandler);
        initiatorNamePanel.setValidator(NameValidator);
        initiatorIPPanel.setValidator(SingleIpAddressValidator);
        initiatorIQNPanel.setValidator(InitiatorNameValidator);
        initiatorNamePanel.setRequired(true);
        initiatorIPPanel.setRequired(true);
        initiatorIQNPanel.setRequired(true);
    }

    private final void formatWidgets() {
        mButtonsHLayout.setWidth(410);
        setWidth(500);
        setHeight(300);
    }

    private final void organizeWidgets() {
        mButtonsHLayout.addMember(mOkButton);
        initiatorsListAddRemovePanel.setMembers(initiatorIPPanel,
                initiatorIQNPanel, initiatorNamePanel);
        mBodyHLayout.setMembers(
                initiatorsListAddRemovePanel);
        addItem(mBodyHLayout);
        addItem(mButtonsHLayout);
    }

    private final boolean validateForms() {
        Boolean isNameValid = initiatorNamePanel.validate();
        Boolean isIqnValid = initiatorIQNPanel.validate();
        Boolean isIpValid = initiatorIPPanel.validate();
        return isNameValid && isIqnValid && isIpValid;
    }

    private final class ButtonClickHandler implements ClickHandler {
        @Override
        public void onClick(ClickEvent event) {
            final Object source = event.getSource();
            if (source == mOkButton) {
                if (validateForms()) {
                    SC.logDebug("Validated");
                }
            }
        }
    }

    private class TextBoxWithTooltipError extends HLayout implements
            IValidationComponent,
            ChangedHandler {
        private static final int CHANGE_WAIT_TIME = 2000; // 2 seconds

        private TextItem mTextItem;
        private DynamicForm mContainerForm;
        private AbstractValidationWrapper mValidationFieldWrapper;

        private final boolean mDisplayMsgOnError;
        private Timer mWaitChangeTimer;

        public TextBoxWithTooltipError() {
            this(true, true);
        }

        /**
         * Constructor
         *
         * @param displayErrorMsg
         *            : display or not error message upon failure of input
         *            validation.
         */
        public TextBoxWithTooltipError(boolean enableValidatorOnBlur,
                boolean displayErrorMsg) {
            super();

            initializeWidgets();
            formatWidgets();
            organizeWidgets();

            mDisplayMsgOnError = displayErrorMsg;

            if (enableValidatorOnBlur) {
                addBlurHandler(onBlurValidationHandler());
            }
        }

        protected BlurHandler onBlurValidationHandler() {
            return new BlurHandler() {
                @Override
                public void onBlur(BlurEvent event) {
                    validate();
                }
            };
        }

        /**
         * All elements under this class get initialized in this method. Used in
         * the constructor.
         */
        public void initializeWidgets() {
            mTextItem = new TextItem();
            mTextItem.setRequired(false);
            mContainerForm = new DynamicForm();
            mContainerForm.setBrowserSpellCheck(Boolean.FALSE);
        }

        /**
         * Styling of all elements in this panel is made here. Used in the
         * constructor.
         */
        public void formatWidgets() {
            mContainerForm.setNumCols(1);
            this.setAutoHeight();
            this.setOverflow(Overflow.VISIBLE);
        }

        /**
         * widgets (layouts) are added to their corresponding parent
         * layouts/widgets in this method. Used in the constructor.
         */
        public void organizeWidgets() {
            mContainerForm.setFields(mTextItem);
            mValidationFieldWrapper = TstTooltipFactory
                    .getValidationWrapper(mContainerForm);
            this.setMembers(mValidationFieldWrapper);
        }

        public void setTextBoxWidth(int width) {
            super.setWidth(width);
            mTextItem.setWidth(width);
            mContainerForm.setWidth(width);
            mValidationFieldWrapper.setWidth(width);
        }

        public void setErrorTooltip(String tooltip) {
            setTooltip(tooltip);
        }

        public void setValidator(RegExpValidator validator) {
            mTextItem.setValidators(validator);
            final String tt = getTooltip();
            if (validator == NameValidator && tt == null
                    && mDisplayMsgOnError) {
                setErrorTooltip("invalid");
            }
        }

        public void setRequired(boolean required) {
            mTextItem.setRequired(required);
        }

        /**
         * Validates the input based on the provided validator.
         *
         * @return true if valid, else false.
         */
        public boolean validate() {
            boolean valid = mContainerForm.validate();
            if (valid
                    && mTextItem.getRequired()
                    && (mTextItem.getValueAsString() == null || mTextItem
                            .getValueAsString().length() == 0)) {
                /*
                 * FIXME: Figure out what is happening here. A call to
                 * organizeWidgets() in the declaring file's organizeWidgets()
                 * call fixes this, though it shouldn't matter. Appears to be a
                 * framework bug.
                 */
                GWT.log("The validate call returned valid for empty text though isRequired is true. Marking this field as invalid.");
                valid = false;
            }
            changeErrorStyle(valid);
            return valid;
        }

        public void changeErrorStyle(boolean valid) {
            /*
             * setValidationError(false... doesn't clear the validation error.
             * Need an additional clear statement to actually clear the error.
             */
            mValidationFieldWrapper.clearValidationError();
            mValidationFieldWrapper.setValidationError(!valid, getTooltip());
        }

        public void clearStyles() {
            changeErrorStyle(true);
        }

        @Override
        public HandlerRegistration addBlurHandler(BlurHandler blurHandler) {
            return mTextItem.addBlurHandler(blurHandler);
        }

        @Override
        public HandlerRegistration addFocusHandler(
                com.smartgwt.client.widgets.form.fields.events.FocusHandler focusHandler) {
            return mTextItem.addFocusHandler(focusHandler);
        }

        @Override
        public void clearValidationError() {
            changeErrorStyle(true);
        }

        @Override
        public void setValidationError() {
            changeErrorStyle(false);
        }

        @Override
        public void setValidationError(boolean indicateValidationError) {
            changeErrorStyle(!indicateValidationError);
        }

        @Override
        public boolean doSupportValidation() {
            return true;
        }

        @Override
        public Rectangle getFormPageRect() {
            return mContainerForm.getPageRect();
        }

        @Override
        public void setWidth(int width) {
            setTextBoxWidth(width);
        }

        @Override
        public void onChanged(ChangedEvent event) {
            System.out.println(new Date().toString() + " got changed event");
            mWaitChangeTimer.cancel();
            // remove error while user is typing
            clearStyles();
            mWaitChangeTimer.schedule(CHANGE_WAIT_TIME);
        }

    }

}
