// cookies standard names
var TEMPORAL_PARAMETERS_COOKIE_NAME = "SettingsSessionCookie";
var PERMANENT_PARAMETERS_COOKIE_NAME = "SettingsCookie";

var COOKIE_EXPIRES_NAME='expires';
var COOKIE_PATH_NAME='path';
var COOKIE_DOMAIN_NAME='domain';
var COOKIE_SECURE_NAME='secure';
var COOKIE_NAMES_ASSIGN_SIGN='=';
var COOKIE_NAMES_SEPARATOR=';';
var COOKIE_PERMANENT_EXPIRES_DATA='Sun, 17-Jan-2038 19:14:07 GMT';
var COOKIE_DEFAULT_PATH=null;

// properties separators
// NOTE: COOKIE_PROPERTY_SEPARATOR MUST NOT BE THE SAME as COOKIE_NAMES_SEPARATOR
// DO NOT USE '#' and '/' symbol within property value
var COOKIE_PROPERTY_SEPARATOR='#';
var COOKIE_PROPERTY_MULTIPLE_VALUES_SEPARATOR='$';
var COOKIE_PROPERTY_ASSIGN_SIGN='=';

var EMPTY_STRING = '';

/**
 * Set new document cookie.
 *
 * @param name cookie name
 * @param value cookie value as string
 * @param expires cookie expiration date as string (in GMT format)
 * @param path path (URL) which cookie is accepted for. as string
 * @param domain domain which cookie is accepted for. as string
 * @param secure should be cookie send using secure protocol or not. as string
 * (acceptable values are 'true' or 'false')
 * @param doc document cookie set for.
 * If null than current document object will be used
 */
function setCookie(name, value, expires, path, domain, secure, doc) {
    var curCookie =
        name + COOKIE_NAMES_ASSIGN_SIGN + value +
        ((expires) ? COOKIE_NAMES_SEPARATOR + " " + COOKIE_EXPIRES_NAME + COOKIE_NAMES_ASSIGN_SIGN + expires : EMPTY_STRING) +
        ((path) ? COOKIE_NAMES_SEPARATOR + " " + COOKIE_PATH_NAME  + COOKIE_NAMES_ASSIGN_SIGN + path : EMPTY_STRING) +
        ((domain) ? COOKIE_NAMES_SEPARATOR + " " + COOKIE_DOMAIN_NAME + COOKIE_NAMES_ASSIGN_SIGN + domain : EMPTY_STRING) +
        ((secure) ? COOKIE_NAMES_SEPARATOR + " " + COOKIE_SECURE_NAME : EMPTY_STRING);

    if ((name + COOKIE_NAMES_ASSIGN_SIGN + escape(value)).length <= 4000) {
        if (doc) {
            doc.cookie = curCookie;
        } else {
            document.cookie = curCookie;
        }
    }
//    alert("Cookie: name="+name+"\n     value="+value);
}

/**
 * Returns whole cookie as string for current document
 *
 * @param name - the name of the cookie to read
 * @param doc - document which contains cookie.
 * If null than current document object will be used
 * @return - whole cookie as string or null if there
 * is no such cookie
 */
function getCookie(name, doc) {
    var prefix = name + COOKIE_NAMES_ASSIGN_SIGN;
    var cookieStartIndex = (doc) ? doc.cookie.indexOf(prefix) : document.cookie.indexOf(prefix);
    if (cookieStartIndex == -1) {
        return null;
    }
    return (doc) ? doc.cookie : document.cookie;
}

/**
 * Deletes cookie from the document. This method just removes cookie content.
 *
 * @param name cookie name
 * @param path path (URL) which cookie is accepted for
 * @param domain domain which cookie is accepted for
 * @param doc document cookie removed from
 * If null than current document object will be used
 */
function deleteCookie(name, path, domain, doc) {
    var cookie = getCookie(name, doc);
    if ((cookie)&&(cookie != EMPTY_STRING)) {
        var target = null;

        if (doc) {
            target = doc;
        } else {
            target = document;
        }
        target.cookie =
        name + COOKIE_NAMES_ASSIGN_SIGN +
        ((path) ? COOKIE_NAMES_SEPARATOR + " "+ COOKIE_PATH_NAME + COOKIE_NAMES_ASSIGN_SIGN + path : EMPTY_STRING) +
        ((domain) ? COOKIE_NAMES_SEPARATOR + " "+ COOKIE_DOMAIN_NAME + COOKIE_NAMES_ASSIGN_SIGN + domain : EMPTY_STRING);
    }
}

/**
 * Function add new property to the given cookie
 * if there is such property (with the same name) it will be overwritten.
 *
 * @param cookieName name of the cookie
 * @param propName name of the property
 * @param propValue value of the property
 * @param doc document cookie changed in
 * If null than current document object will be used
 */
function setCookieProperty(cookieName, propName, propValue, doc) {

    // do not change cookie if value is not changed
    if (getCookie(cookieName, doc) == null) {
        setCookie(cookieName, '', null, COOKIE_DEFAULT_PATH, null, null, doc);
    }

    if (getCookieProperty(cookieName, propName, doc) != propValue) {
        var cookieValue = getCookieValueByName(cookieName, null, doc);
        var cookieExpires = getCookieValueByName(cookieName, COOKIE_EXPIRES_NAME, doc);
        var cookiePath = getCookieValueByName(cookieName, COOKIE_PATH_NAME, doc);
        var cookieDomain = getCookieValueByName(cookieName, COOKIE_DOMAIN_NAME, doc);
        var cookieSecure = getCookieValueByName(cookieName, COOKIE_SECURE_NAME, doc);

        // change cookie value here
        if (cookieValue != null) {

            // check if property exists
            var cookiePropertyPerfix = COOKIE_PROPERTY_SEPARATOR + propName + COOKIE_PROPERTY_ASSIGN_SIGN;
            var cookiePropertyStartIndex = cookieValue.indexOf(cookiePropertyPerfix);

            // if property exists
            if (cookiePropertyStartIndex != -1) {

                var cookiePropertyEndIndex = cookieValue.indexOf(COOKIE_PROPERTY_SEPARATOR,
                    cookiePropertyStartIndex + cookiePropertyPerfix.length);

                if (cookiePropertyEndIndex == -1) {
                    cookiePropertyEndIndex = cookieValue.length;
                }

                // replace old value with new one
                var stringBefore = cookieValue.substring(0, cookiePropertyStartIndex + cookiePropertyPerfix.length);
                var stringAfter = cookieValue.substring(cookiePropertyEndIndex, cookieValue.length);
                cookieValue = stringBefore + assembleProperty(propValue) + stringAfter;
            } else {

                // there is no such property just add it after separator
                cookieValue = cookieValue + COOKIE_PROPERTY_SEPARATOR
                    + propName + COOKIE_PROPERTY_ASSIGN_SIGN + assembleProperty(propValue);
            }
        } else {

            // cookie value is empty just add
            cookieValue = COOKIE_PROPERTY_SEPARATOR + propName + COOKIE_PROPERTY_ASSIGN_SIGN + assembleProperty(propValue);
        }

        // set new cookie
        setCookie(cookieName, cookieValue, cookieExpires, cookiePath, cookieDomain, cookieSecure, doc);
    }
}


/**
 * Function assembles multiple property values to the single string
 *
 * @param propValue value of the property
 * @return assembled property. If property value is null - returns null.
 * If property value is a single string than method returns given string.
 * If property value is an array of values than method returns
 */
function assembleProperty(propValue) {
    var result = EMPTY_STRING;
    if ((typeof propValue) == 'object') {
        for(var i = 0; i < propValue.length; i++) {
            result = result + propValue[i];
            if (i != (propValue.length - 1)) {
                result = result + COOKIE_PROPERTY_MULTIPLE_VALUES_SEPARATOR;
            }
        }
    } else {
        result = propValue;
    }
    return result;
}

/**
 * Function returns property from the given cookie. If property is multiply values one
 * function will split all values and returns array.
 *
 * @param cookieName name of the cookie
 * @param propName name of the property
 * @param doc document cookie got from
 * If null current document object will be used
 * @return array of values. If there is no such property or value is empty than empty
 * array will be returned as result. If property is a single value one than array with 1 element
 * will be returned. If the given property is multiple value one than array with all elements
 * will be returned
 *
 */
function getCookieProperty(cookieName, propName, doc) {

    var result = null;

    var cookieValue = getCookieValueByName(cookieName, null, doc);

    if (cookieValue != null) {

        // check if property exists
        var cookiePropertyPerfix = COOKIE_PROPERTY_SEPARATOR + propName + COOKIE_PROPERTY_ASSIGN_SIGN;
        var cookiePropertyStartIndex = cookieValue.indexOf(cookiePropertyPerfix);

        // if property exists
        if (cookiePropertyStartIndex != -1) {
            var cookiePropertyEndIndex = cookieValue.indexOf(COOKIE_PROPERTY_SEPARATOR,
                cookiePropertyStartIndex + cookiePropertyPerfix.length);

            if (cookiePropertyEndIndex == -1) {
                cookiePropertyEndIndex = cookieValue.length;
            }
            result = cookieValue.substring(cookiePropertyStartIndex + cookiePropertyPerfix.length,
                cookiePropertyEndIndex);
        }
    }
    return (result == null) ? new Array() : result.split(COOKIE_PROPERTY_MULTIPLE_VALUES_SEPARATOR);
}

/**
 * Function removes property from the given cookie
 * if there is such property (with the same name) it will be overwritten.
 *
 * @param cookieName name of the cookie
 * @param propName name of the property
 * @param doc document cookie changed in
 * If null than current document object will be used
 */
function removeCookieProperty(cookieName, propName, doc) {

    // do not change cookie if value is not changed
    if (getCookie(cookieName, doc) == null) {
        setCookie(cookieName, '', null, null, null, null, doc);
    }

    if (getCookieProperty(cookieName, propName, doc) != null) {
        var cookieValue = getCookieValueByName(cookieName, null, doc);
        var cookieExpires = getCookieValueByName(cookieName, COOKIE_EXPIRES_NAME, doc);
        var cookiePath = getCookieValueByName(cookieName, COOKIE_PATH_NAME, doc);
        var cookieDomain = getCookieValueByName(cookieName, COOKIE_DOMAIN_NAME, doc);
        var cookieSecure = getCookieValueByName(cookieName, COOKIE_SECURE_NAME, doc);

        // change cookie value here
        if (cookieValue != null) {

            // check if property exists
            var cookiePropertyPerfix = propName + COOKIE_PROPERTY_ASSIGN_SIGN;
            var cookiePropertyStartIndex = cookieValue.indexOf(cookiePropertyPerfix);
            // if property exists
            if (cookiePropertyStartIndex != -1) {

                var cookiePropertyEndIndex = cookieValue.indexOf(COOKIE_PROPERTY_SEPARATOR,
                        cookiePropertyStartIndex + cookiePropertyPerfix.length);


                if (cookiePropertyEndIndex == -1) {
                    // to the end of the string
                    cookiePropertyEndIndex = cookieValue.length;

                    // remove previous separator
                    if (cookiePropertyStartIndex != 0) {
                        cookiePropertyStartIndex--;
                    }
                } else {
                    // remove separator too
                    cookiePropertyEndIndex++;
                }

                // remove value

                // if cookiePropertyStartIndex
                var stringBefore = cookieValue.substring(0, cookiePropertyStartIndex);
                var stringAfter = cookieValue.substring(cookiePropertyEndIndex, cookieValue.length);
                cookieValue = stringBefore + stringAfter;
            }
        }
        // set new cookie
        setCookie(cookieName, cookieValue, cookieExpires, cookiePath, cookieDomain, cookieSecure, doc);
    }
}


/**
 * Function returns value of the given cookie as string;
 *
 * @param cookieName name of the cookie
 * @param valueName name of the cookie parameter (like expires, path or domain).
 * If this parameter is empty than value of the cookie will return
 * @param doc document cookie got from
 * If null than current document object will be used
 * @return null if there is no such cookie or 'valueName' value.
 */
function getCookieValueByName(cookieName, valueName, doc) {
    var result = null;

    // get whole cookie
    var cookie = getCookie(cookieName, doc);

    // if cookie exists
    if (cookie != null) {

        // get cookie value
        var prefix = (((valueName)&&(valueName != EMPTY_STRING)) ? valueName : cookieName) + COOKIE_NAMES_ASSIGN_SIGN;
        var cookieStartIndex = cookie.indexOf(prefix);
        if (cookieStartIndex != -1) {

            var cookieEndIndex = cookie.indexOf(COOKIE_NAMES_SEPARATOR, cookieStartIndex + prefix.length);
            if (cookieEndIndex == -1) {
                cookieEndIndex = cookie.length;
            }
            result = cookie.substring(cookieStartIndex + prefix.length, cookieEndIndex);
        }
    }
    return result;
}

/**
 * Function saves one cookie (f.e. with session scope) as a permanent cookie
 *
 * @param temporalCookieName name of saved cookie
 * @param permanentCookieName name of permanent cookie
 * @param doc document cookie saves to
 */
function saveCookie(temporalCookieName, permanentCookieName, doc) {

    // do not change cookie if value is not changed
    var cookieValue = getCookieValueByName(temporalCookieName, null, doc);
    var cookiePath = getCookieValueByName(temporalCookieName, COOKIE_PATH_NAME, doc);
    var cookieDomain = getCookieValueByName(temporalCookieName, COOKIE_DOMAIN_NAME, doc);
    var cookieSecure = getCookieValueByName(temporalCookieName, COOKIE_SECURE_NAME, doc);

    setCookie(permanentCookieName, cookieValue, COOKIE_PERMANENT_EXPIRES_DATA,
        cookiePath, cookieDomain, cookieSecure, doc);

    // to make it permanent;
//    loadCookie(temporalCookieName, permanentCookieName, doc);
}

/**
 * Function loads permanent cookie and stores it as a temporary one.
 *
 * @param temporalCookieName name of saved cookie
 * @param permanentCookieName name of permanent cookie
 * @param doc document cookie loads to
 */
function loadCookie(temporalCookieName, permanentCookieName, doc) {
    // do not change cookie if value is not changed
    var cookieValue = getCookieValueByName(permanentCookieName, null, doc);
    var cookiePath = getCookieValueByName(permanentCookieName, COOKIE_PATH_NAME, doc);
    var cookieDomain = getCookieValueByName(permanentCookieName, COOKIE_DOMAIN_NAME, doc);
    var cookieSecure = getCookieValueByName(permanentCookieName, COOKIE_SECURE_NAME, doc);

    setCookie(temporalCookieName, cookieValue, null, cookiePath, cookieDomain, cookieSecure, doc);
}

/**
 * Function find cookie in the given document end creates the same one within the current document
 *
 * @param cookieName name of the cookie to export
 * @param doc document where cookie will find
 */
function exportCookie(cookieName, doc) {
    // do not change cookie if value is not changed
    var cookieValue = getCookieValueByName(cookieName, null, doc);
    var cookiePath = getCookieValueByName(cookieName, COOKIE_PATH_NAME, doc);
    var cookieDomain = getCookieValueByName(cookieName, COOKIE_DOMAIN_NAME, doc);
    var cookieSecure = getCookieValueByName(cookieName, COOKIE_SECURE_NAME, doc);

    setCookie(cookieName, cookieValue, null, cookiePath, cookieDomain, cookieSecure);
}

