/*
 * Copyright 2009 Smilehouse Oy.
 */
/*
 * version 1.0, 17.6.2009
 * 
 * Character set encoding for this file must be UTF-8.
 * 
 * This version fixes the problems with delivery address fields when using
 * back button, especially on further orders during the same session.
 * Uses a cookie to hold the noutopiste delivery address fields; cookie
 * seems to be about only thing that gets reliably updated through different
 * pages and back-button presses.
 * 
 * Note that the order pages (and their functionality) depends on the class
 * of submit buttons. If they are modified, modify this script, too.
 */
$(document).ready(function() {

    // **********************************************************************
    //  SETTINGS
    //  Change these values to match your site's order form.
    // **********************************************************************

    // Shipping method name for noutopiste
    var NP_SHIPPING_METHOD_NAME = "Postin noutopiste";

    // Shipping method select field ID
    var NP_SHIPPING_SELECT_ID = "ws11";

    // ID of the previous element, after which the search form is to be
    // places. If empty, the form will be placed as the first element in
    // the order form.
    var NP_INSERT_AFTER_ID = "ws11";

    // IDs of the customer question fields for the delivery address
    // (correspond to search result parameters LabelPostOffice, LabelAddress,
    // LabelPostCode, LabelCity);
    // to be filled when search and select is performed.
    var NP_POSTOFFICE_FIELD_ID = "user201";
    var NP_ADDRESS_FIELD_ID = "ws20";
    var NP_POSTALCODE_FIELD_ID = "ws21";
    var NP_CITY_FIELD_ID = "ws22";

    // IDs of the hidden form fields for saving previous data.
    // NOTE! Corresponding hidden fields need to be created in Workspace.
    var NP_SEARCH_TMP = "user202";
    var NP_ADDRESS_TMP = "user203";
    var NP_SEARCH_STATUS = "user204";



    // SEARCH FORM HTML CODE
    // =====================
    var NP_SEARCH_FORM_HTML =
        '<tr id="np_search">'
        +'<td colspan="2">'
        +'<div style="margin: 10px; padding: 5px; border: 2px solid #aaaaaa">'
        +'<table><tr>'
        +'<td valign="top" align="right">'
        +'<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#000000">'
        +'<label for="np_city_error"><strong>Kaupunki:</strong></label>'
        +'</font>'
        +'</td>'
        +'<td valign="top" align="left">'
        +'<div id="np_city_error" class="np_error"></div>'
        +'<input type="text" name="" id="np_search_city" maxlength="200" />'
        +'</td>'
        +'</tr><tr>'
        +'<td valign="top" align="right">'
        +'<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#000000">'
        +'<label for="np_search_area"><strong>Alue:</strong></label>'
        +'</font>'
        +'</td>'
        +'<td valign="top" align="left">'
        +'<div id="np_area_error" class="np_error"></div>'
        +'<input type="text" name="" id="np_search_area" maxlength="200" />'
        +'</td>'
        +'</tr><tr>'
        +'<td valign="top" align="right">'
        +'<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#000000">'
        +'<label for="np_search_postalcode"><strong>Postinumero:</strong></label>'
        +'</font>'
        +'</td>'
        +'<td valign="top" align="left">'
        +'<div id="np_postalcode_error" class="np_error"></div>'
        +'<input type="text" name="" id="np_search_postalcode" maxlength="200" />'
        +'</td>'
        +'</tr><tr>'
        +'<td valign="top" align="right"></td>'
        +'<td valign="top" align="left">'
        +'<input type="submit" name="np_submit" id="np_submit" value="Hae" />'
        +'</td>'
        +'</tr><tr>'
        +'<td valign="top" align="right">'
        +'<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#000000">'
        +'<label for="np_location_select"><strong>Valitse noutopiste:</strong></label>'
        +'</font>'
        +'</td>'
        +'<td valign="top" align="left" id="np_location">'
        +'K&auml;yt&auml; yll&auml;olevaa hakua noutopisteiden etsimiseen.'
        +'</td>'
        +'</tr></table>'
        +'</div>'
        +'</td>'
        +'</tr>';


    // MESSAGES
    // ========
    // Displayed above a search field when it contains errors.
    var field_error_message =
        "Kentt&auml; sis&auml;lt&auml;&auml; laittomia merkkej&auml;:\n";

    // Alert header displayed when the search form is submitted
    // with illegal characters
    var invalid_fields_message = "Tarkasta seuraavat:";

    // Message to be displayed when search form is submitted with all
    // search fields empty
    var no_search_params = "Ole hyvä ja anna vähintään yksi hakuparametri!";

    // Message to be displayed when search is in progress
    var search_in_progress = "Haetaan...";

    // Message to be displayed instead of select list when search fields contain
    // invalid characters.
    var search_params_invalid = "Virheellinen haku...";

    // Alert message to be displayed when for some reason the delivery address
    // fields are not correct when trying to submit the order form:
    var MSG_INVALID_DELIVERY_ADDRESS_FIELDS = "Toimitusosoitekentät tyhjiä tai virheellisiä, hae ja/tai valitse noutopiste."; 

    // **********************************************************************
    // SETTINGS END!
    // DO NOT EDIT BELOW THIS LINE!
    // **********************************************************************




    // Internal session cookie (needed to get around problems coming with the
    // use of back button between order form and confirm pages, on some browsers)
    var COOKIE_NAME = "WS-noutopiste-temporary";

    // REGULAR EXPRESSIONS FOR CHECKING SEARCH FIELDS
    // ==============================================
    // Regulare expression for city and area
    var allowed_string =
        new RegExp("^[a-zåäöÅÄÖ, -]*$", "i");

    // Regular expression for postal code
    var allowed_numeric = new RegExp("^[0-9, -]*$", "i");

    // value will be 1 or 2 if the script is on order form page or order confirm
    // page, respectively.
    var page = -1;

    // =====================================================
    // INITIALIZATION CODE
    // Executed as soon as DOM has been loaded and is ready for javascript messing.
    // These if's check existence of the submit buttons to detect when
    // the javascript is being executed on order form/confirm page.
    if ($(".OrderFormSendButton").length != 0) {
        page = 1;
        // Clear the delivery address fields initially.
        if (getSearchDoneStatus() == "0")
            clearDeliveryAddressFields();
        // Bind a handler to react to shippin method change
        $("#" + NP_SHIPPING_SELECT_ID).change(handle_shipping_change_event);
        // Check if noutopiste search form was visible when order form was
        // submitted (in case of errors) or if it's selected by default
        if (getSearchFormStatus() == 1
                || $("#" + NP_SHIPPING_SELECT_ID).val() == NP_SHIPPING_METHOD_NAME) {
            handle_shipping_select();
        }
        // Bind a handler to react to order form submit
        $(".OrderFormSendButton").click(orderFormSubmit);
        
        activateTimerTask();
    } else if ($(".OrderFormConfirmButton").length != 0) {
        page = 2;
        // Bind a handler to react to confirm form submit
        $(".OrderFormConfirmButton").click(confirmFormSubmit);
    }
    // END OF INITIALIZATION CODE
    // =======================================================

    // =======================================================================
    // Timer task
    // This "running" process is used to "fix" the delivery address fields
    // when the browser messes them up, until the user selects an address
    // (at which point it is 100% sure the browser has done its messing ups
    // and is no longer a problem, and the process can be stopped).
    var browserStupidityCheckTimerId = null;

    function activateTimerTask() {
        browserStupidityCheckTimerId = window.setTimeout(timerTask, 100);
    }

    function stopTimerTask() {
        if (browserStupidityCheckTimerId != null) {
            window.clearTimeout(browserStupidityCheckTimerId);
            browserStupidityCheckTimerId = null;
        }
    }

    function timerTask() {
        stopTimerTask();
        if ((page == 1) && (getSearchFormStatus() == 1)) {
            restoreNPDeliveryAddressFields();
        }
        activateTimerTask();
    }

    // =======================================================================
    // FUNCTIONS
    // =========
    
    function handle_shipping_change_event() {
        if (!isShippingSelectOnPage()) // Redundant, but just in case...
            return;
        // Was "noutopiste" selected or unselected?
        if ($("#" + NP_SHIPPING_SELECT_ID).val() == NP_SHIPPING_METHOD_NAME) {
            saveManualDeliveryAddressFields();
            noutopiste_selected();
            restoreNPDeliveryAddressFields();
        } else if (getSearchFormStatus() == 1) {
            // Some other shipping method was selected and the form is visible
            saveNPDeliveryAddressFields();
            noutopiste_unselected();
            restoreManualDeliveryAddressFields();
        }
    }

    // ----------------------------------------------------------------------
    // Checks if noutopiste is selected and displays or hides the search form
    // as necessary.
    // ----------------------------------------------------------------------
    function handle_shipping_select() {
        if (!isShippingSelectOnPage()) // Redundant, but just in case...
            return;
        // Check if noutopiste was selected
        if ($("#" + NP_SHIPPING_SELECT_ID).val() == NP_SHIPPING_METHOD_NAME) {
            noutopiste_selected();
        } else if (getSearchFormStatus() == 1) {
            // Some other shipping method was selected and the form is visible
            noutopiste_unselected();
        }
    }

    // Changes situation to noutopiste; shows search form and disables manual changes
    // to the delivery address fields.
    function noutopiste_selected() {
        // Insert seach form...
        if (NP_INSERT_AFTER_ID) {
            // ... before given element if element ID is given
            $("#" + NP_INSERT_AFTER_ID).parent().parent().after(NP_SEARCH_FORM_HTML);
        } else {
            // ... as the first visible element in the form
            $("#ws1").parent().parent().before(NP_SEARCH_FORM_HTML);
        }

        disableDeliveryAddressFields();

        // Check if noutopiste search form was used before and use the
        // previous data if available
        if ($("#" + NP_SEARCH_TMP).val() != "") {
            restoreSearchValues();
            // Check search form values
            checkCity();
            checkArea();
            checkPostalcode();
        }
        setSearchFormStatus(1); // Set search form status to visible

        // Bind validation functions to search fields (These
        // functions are called when field value is changed)
        $("#np_search_city").keyup(checkCity);
        $("#np_search_area").keyup(checkArea);
        $("#np_search_postalcode").keyup(checkPostalcode);

        // Bind a handler function for search form submit button
        $("#np_submit").click(performSearch);
        // Register event listener for search result:
        WSAjaxLib.Events.registerEventHandler("noutopiste.results", searchResponseHandler);
    }

    // Changes situation to manual delivery address fields and hides the search form.
    function noutopiste_unselected() {
        enableDeliveryAddressFields();
        saveSearchValues(); // Save current search form values
        $("#np_search").remove(); // Hide the search form
        setSearchFormStatus(0); // Set search form status to hidden
    }

    // ----------------------------------------------------------------------
    // Function to act when search form submit is pressed.
    // Calls a check for all search form fields and starts the search
    // if everything is ok.
    // ----------------------------------------------------------------------
    function performSearch() {
        // Save current search form values
        saveSearchValues();

        if (checkFields()) {
            $("#np_location").html(search_in_progress);
            WSAjaxLib.NoutopisteRekisteri.search(
                $("#np_search_city").val(),
                $("#np_search_area").val(),
                $("#np_search_postalcode").val()
            );

            setSearchDoneStatus(1);
        }
        else {
            $("#np_location").html(search_params_invalid);
        }
        return false;
    }

    function searchResponseHandler(event) {
        // Expecting an array of objects, each object holding one search match result.
        var responseArray = event.params;
        // Check for error-object and inject proper message instead of selection box:
        if (!jQuery.isArray(responseArray)) {
            $("#np_location").html(responseArray["failuremessage"]);
            return;
        }
        
        // Pick up the necessary data from the response elements and create
        // selection options:
        var options = new Array();
        for (var i = 0; i < responseArray.length; i++) {
            var resp = responseArray[i];
            var entry = new Object();
            entry["optionValue"] = trim(resp["LabelPostOffice"]) + ":"
                + trim(resp["LabelAddress"]) + ":"
                + trim(resp["LabelPostCode"]) + ":"
                + trim(resp["LabelCity"]);
            entry["optionDisplay"] = trim(resp["Address"]) + ", "
                + prettyName(trim(resp["City"]));
            if (resp["Availability"] != "")
                entry["optionDisplay"] += " (" + resp["Availability"]+ ")";
            options.push(entry);
        }
        listPlaces(options);
    }

    function orderFormSubmit() {
        // Enable address fields again just before submit
        enableDeliveryAddressFields();
        // only check delivery addresses if noutopiste delivery method is selected
        if ($("#" + NP_SHIPPING_SELECT_ID).val() == NP_SHIPPING_METHOD_NAME) {
            if (!checkDeliveryAddressFields()) {
                alert(MSG_INVALID_DELIVERY_ADDRESS_FIELDS);
                return false;
            }
        }
        saveNPDeliveryAddressFields();
        return true;
    }

    function confirmFormSubmit() {
        setSearchDoneStatus(0);
        setCookie(COOKIE_NAME, "", -1);
        clearTemporaries();
        return true;
    }

    // ----------------------------------------------------------------------
    // Function to create a select list of available noutopiste locations.
    // ----------------------------------------------------------------------
    function listPlaces(places) {
        var options = '';

        // Create options list for select
        jQuery.each(places, function(i, place) {
            options += '<option value="' + place.optionValue + '">' +
                place.optionDisplay + '</option>';
        });

        // Select field html code
        var select_code =
            '<select name="" id="np_location_select">'
            + '<option value="0">Valitse noutopiste</option>'
            + options
            +'</select>';

        // Insert select field into html
        $("#np_location").html(select_code);

        // Register a handler function for select field change
        $("#np_location_select").change(function() {
            if ($("#np_location_select option:selected").val() == '0') {
                return;
            }
            if (browserStupidityCheckTimerId != null) {
                stopTimerTask();
                window.setTimeout(setDeliveryAddressFields, 100);
            } else {
                setDeliveryAddressFields();
            }
        });
    }

    // =======================================================================

    // ----------------------------------------------------------------------
    // Function to check search form's city field.
    // Check that city field contains only allowed characters.
    // ----------------------------------------------------------------------
    function checkCity() {
        // Test field against allowed_string regexp
        if (!allowed_string.test($("#np_search_city").val())) {
            $("#np_city_error").html(field_error_message);
        }
        else {
            $("#np_city_error").html("");
        }
    }

    // ----------------------------------------------------------------------
    // Function to check search form's area field.
    // Check that area field contains only allowed characters.
    // ----------------------------------------------------------------------
    function checkArea() {
        // Test field against allowed_string regexp
        if (!allowed_string.test($("#np_search_area").val())) {
            $("#np_area_error").html(field_error_message);
        }
        else {
            $("#np_area_error").html("");
        }
    }

    // ----------------------------------------------------------------------
    // Function to check search form's postal code field.
    // Check that postal code field contains only allowed characters.
    // ----------------------------------------------------------------------
    function checkPostalcode() {
        // Test field against allowed_numeric regexp
        if (!allowed_numeric.test($("#np_search_postalcode").val())) {
            $("#np_postalcode_error").html(field_error_message);
        }
        else {
            $("#np_postalcode_error").html("");
        }
    }

    // ----------------------------------------------------------------------
    // Function for testing noutopiste search form fields when submitted.
    // Checks that at least one search form field contains something other
    // than spaces and that all fields contain only valid characters.
    // ----------------------------------------------------------------------
    function checkFields() {
        var errors_found = false;

        var message = invalid_fields_message + "\n";

        var city_value = $("#np_search_city").val();
        var area_value = $("#np_search_area").val();
        var postalcode_value = $("#np_search_postalcode").val();

        // Check that at least one field contains something
        if (trim(city_value) == "" && trim(area_value) == "" &&
            trim(postalcode_value) == "") {
            $("#np_location").html(search_params_invalid);

            alert(no_search_params);

            return false;
        }

        // Check city field
        if (!allowed_string.test(city_value)) {
            message += "- kaupunki\n";
            errors_found = true;
        }

        // Check area field
        if (!allowed_string.test(area_value)) {
            message += "- alue\n";
            errors_found = true;
        }

        // Check postal code field
        if (!allowed_numeric.test(postalcode_value)) {
            message += "- postinumero\n";
            errors_found = true;
        }

        // Display errors if some field contains invalid character
        if (errors_found) {
            $("#np_location").html(search_params_invalid);

            alert(message);

            return false;
        }

        return true;
    }


    // ================================================================

    function isShippingSelectOnPage() {
        return $("#" + NP_SHIPPING_SELECT_ID).length != 0
            && $("#" + NP_SHIPPING_SELECT_ID)[0].tagName.toLowerCase() == "select";
    }

    function enableDeliveryAddressFields() {
        $("#" + NP_POSTOFFICE_FIELD_ID).removeAttr("disabled");
        $("#" + NP_ADDRESS_FIELD_ID).removeAttr("disabled");
        $("#" + NP_POSTALCODE_FIELD_ID).removeAttr("disabled");
        $("#" + NP_CITY_FIELD_ID).removeAttr("disabled");
    }

    function disableDeliveryAddressFields() {
        $("#" + NP_POSTOFFICE_FIELD_ID).attr("disabled", "disabled");
        $("#" + NP_ADDRESS_FIELD_ID).attr("disabled", "disabled");
        $("#" + NP_POSTALCODE_FIELD_ID).attr("disabled", "disabled");
        $("#" + NP_CITY_FIELD_ID).attr("disabled", "disabled");
    }

    function clearDeliveryAddressFields() {
        setDeliveryAddressFieldValues(":::");
    }

    function setDeliveryAddressFields() {
        var selected_place_value = $("#np_location_select option:selected").val();
        setDeliveryAddressFieldValues(selected_place_value);
    }

    // Save current manual input delivery address values to hidden fields
    function saveManualDeliveryAddressFields() {
        var address_data = getDeliveryAddressFieldValues();
        $("#" + NP_ADDRESS_TMP).val(address_data);
    }

    function restoreManualDeliveryAddressFields() {
        // Get previous address values from hidden address field
        var restore_data = $("#" + NP_ADDRESS_TMP).val();
        // Restore previous address values to corresponding data fields
        setDeliveryAddressFieldValues(restore_data);
    }

    // Save current delivery address values to cookie
    function saveNPDeliveryAddressFields() {
        var address_data = getDeliveryAddressFieldValues();
        setCookie(COOKIE_NAME, address_data, null);
    }

    function restoreNPDeliveryAddressFields() {
        // Get previous address values from cookie
        var cookiedata = getCookie(COOKIE_NAME);
        if (cookiedata != null)
            restore_data = cookiedata;
        else
            restore_data = ":::";
        // Restore previous address values to corresponding data fields
        setDeliveryAddressFieldValues(restore_data);
    }

    function checkDeliveryAddressFields() {
        if (trim($("#" + NP_POSTOFFICE_FIELD_ID).val()) == "") return false;
        if (trim($("#" + NP_ADDRESS_FIELD_ID).val()) == "") return false;
        if (trim($("#" + NP_POSTALCODE_FIELD_ID).val()) == "") return false;
        if (trim($("#" + NP_CITY_FIELD_ID).val()) == "") return false;
        if ($("#np_location_select").length != 0) {
            // Noutopiste search done
            if ($("#np_location_select option:selected").val() != '0') {
                // Some noutopiste selected
                selected_place = $("#np_location_select option:selected").val().split(":");
                if ($("#" + NP_POSTOFFICE_FIELD_ID).val() != selected_place[0]) return false;
                if ($("#" + NP_ADDRESS_FIELD_ID).val() != selected_place[1]) return false;
                if ($("#" + NP_POSTALCODE_FIELD_ID).val() != selected_place[2]) return false;
                if ($("#" + NP_CITY_FIELD_ID).val() != selected_place[3]) return false;
            }
        }
        return true;
    }

    function getDeliveryAddressFieldValues() {
        var address_data = [];
        address_data[0] = $("#" + NP_POSTOFFICE_FIELD_ID).val();
        address_data[1] = $("#" + NP_ADDRESS_FIELD_ID).val();
        address_data[2] = $("#" + NP_POSTALCODE_FIELD_ID).val();
        address_data[3] = $("#" + NP_CITY_FIELD_ID).val();
        return address_data.join(":");
    }

    function setDeliveryAddressFieldValues(values) {
        var separatedValues = values.split(":");
        $("#" + NP_POSTOFFICE_FIELD_ID).val(separatedValues[0]);
        $("#" + NP_ADDRESS_FIELD_ID).val(separatedValues[1]);
        $("#" + NP_POSTALCODE_FIELD_ID).val(separatedValues[2]);
        $("#" + NP_CITY_FIELD_ID).val(separatedValues[3]);
    }


    // ----------------------------------------------------------------------
    // Saves noutopiste search form values to a hidden field.
    // ----------------------------------------------------------------------
    function saveSearchValues() {
        // Get values from noutopiste search form
        var search_form_values = [];
        search_form_values[0] = $("#np_search_city").val();
        search_form_values[1] = $("#np_search_area").val();
        search_form_values[2] = $("#np_search_postalcode").val();
        // Save values to hidden form field
        $("#" + NP_SEARCH_TMP).val(search_form_values.join(":"));
    }

    function restoreSearchValues() {
        // Get previous data from hidden field
        var previous_search_data = $("#" + NP_SEARCH_TMP).val();
        var previous_search_array = previous_search_data.split(":");
        // Restore previous user values to corresponding data fields
        $("#np_search_city").val(previous_search_array[0]);
        $("#np_search_area").val(previous_search_array[1]);
        $("#np_search_postalcode").val(previous_search_array[2]);
    }

    function getSearchFormStatus(value) {
        if (trim($("#" + NP_SEARCH_STATUS).val()) == "")
            return 0;
        var status = $("#" + NP_SEARCH_STATUS).val().split(":");
        return status[0];
    }

    function setSearchFormStatus(value) {
        var status = [value, getSearchDoneStatus()];
        $("#" + NP_SEARCH_STATUS).val(status.join(":"));
    }

    function getSearchDoneStatus(value) {
        if (trim($("#" + NP_SEARCH_STATUS).val()) == "")
            return 0;
        var status = $("#" + NP_SEARCH_STATUS).val().split(":");
        return status[1];
    }

    function setSearchDoneStatus(value) {
        var status = [getSearchFormStatus(), value];
        $("#" + NP_SEARCH_STATUS).val(status.join(":"));
    }

    function clearTemporaries() {
        // NP_SEARCH_TMP is left as is; contains the used search parameters; might be useful next time.
        $("#" + NP_SEARCH_STATUS).val("");
        $("#" + NP_ADDRESS_TMP).val("");
    }


    // ----------------------------------------------------------------------
    // String trimming function, removes all whitespaces from the beginning
    // and the end of the string.
    // ----------------------------------------------------------------------
    function trim(text) {
        return text.replace(/^\s+|\s+$/g, "");
    }

    // Converts a string with random upper/lowercase letters to capitalized
    // first letter and all the rest in lowercase. Per word or parts of word
    // separated with '-'.
    function prettyName(name) {
        var parts1 = name.split(" ");
        for (var i1 = 0; i1 < parts1.length; i1++) {
            var part1 = parts1[i1];
            var parts2 = part1.split("-");
            for (var i2 = 0; i2 < parts2.length; i2++) {
                // Capitalize and make rest lowercase for each "part":
                var s = parts2[i2];
                s = s.substring(0, 1).toLocaleUpperCase() + s.substring(1, s.length).toLocaleLowerCase();
                parts2[i2] = s;
            }
            parts1[i1] = parts2.join("-");
        }
        return parts1.join(" ");
    }


    //  Cookie handling, time in seconds
    function setCookie(name, value, time) {
        var exp = "";
        if (time) {
            var date = new Date();
            date.setTime(date.getTime() + time * 1000);
            exp = "; expires=" + date.toGMTString();
        }
        document.cookie = name + "=" + encodeURIComponent(value) + exp + "; path=/";
    }

    function getCookie(name) {
        if (name == null) return null;
        var cookies = document.cookie.split(';');
        if (cookies.length < 1) return null;
        for (var i = 0; i < cookies.length; i++) {
            var coo = cookies[i];
            coo = coo.replace(/^\s+/g, "");
            var idx = coo.indexOf('=');
            if (idx < 0) {
                // only cookie name, no '=' or value
                if (coo != name) continue;
                return "";
            } else {
                if (coo.substring(0, idx) != name)
                    continue;
                return decodeURIComponent(coo.substring(idx+1, coo.length));
            }
        }
        return null;
    }

});

