﻿// Author: Entropy
// Version: 1.0

/*class*/
function StorageCookie(name/*:String*/, fields/*:Array*/) {
    if (!arguments.length) return;

    this.name = name;
    this.fields = fields;
    this.records = {};

    var value = getCookie(name);
    if (!value) return;

    // Получаем записи из куки.
    var record, id;
    var values = value.split("&");
    while (values.length > 0) {
        record = {};
        for (var i = 0; i < this.fields.length; i++) {
            record[fields[i]] = decodeURIComponent(values.shift());
        }
        this.records["_" + record.id] = record;
    }
}

StorageCookie.prototype = {
    /**
     * Вставляет запись, если id существует, то запись не замещается.
     * Возвращает истину, если новая запись вставлена.
     */
    insert: function (record/*:Record*/)/*:Boolean*/ {
        if (this.records["_" + record.id] != null) return false;
        this.records["_" + record.id] = record;
        return true;
    },
    /**
     * Вставляет запись, если id существует, то запись замещается.
     */
    replace: function (record/*:Record*/)/*:Void*/ {
        this.records["_" + record.id] = record;
    },

    getLength: function ()/*:Number*/ {
        var result = 0;
        for (record in this.records) result++;
        return result;
    },
    /**
     * Удаляет запись с определенным id. Если id не указан, удаляет все.
     */
    remove: function (id/*:Number*/)/*:Void*/ {
        if (id)
            delete this.records["_" + id];
        else
            this.records = {};
    },

    /**
     * Возврвщает объект объектов, соответствующих условию,
     * Если id не указан, возвращаются все записи.
     */

    select: function (id)/*:Object*/ {
        return id ? this.records["_" + id] : this.records;
    },

    //name, value, seconds, path, domain, secure

    set: function (path/*:String*/, seconds/*:Number*/, domain/*:String*/, secure)/*:Void*/ {
        var value = "";

        for (var recordName in this.records) {
            for (var i = 0; i < this.fields.length; i++) {
                value += "&" + encodeURIComponent(this.records[recordName][this.fields[i]]);
            }
        }
        setCookie(this.name, value.substring(1), seconds, path, domain, secure);
    }
};

function saveToCookies(records, name, path/*:String*/, seconds/*:Number*/, domain/*:String*/, secure)/*:Void*/ {
    function hasEnumerableProperties(object) {
        for (var key in object) {
            return key !== undefined;
        }
    }
    var value = "";
    if (hasEnumerableProperties(records)) {
        for (var recordKey in records) {
            var record = records[recordKey];
            var fields = [];
            var fieldNames = [];
            for (var propertyName in record) {
                var propertyValue = record[propertyName];
                fields.push(propertyName + ":" + typeof propertyValue);
                fieldNames.push(propertyName);
            }
            fields.sort();
            fieldNames.sort();
            if (fields == undefined) {
                alert(777);
            }
            for (var i = 0; i < fields.length; i++) {
                value += "&" + encodeURIComponent(record[fieldNames[i]]);
            }
        }
        var fieldsValue = fields.join(",");
    } else {
        var fieldsValue = "";
    }


    setCookie(name, fieldsValue + value, seconds, path, domain, secure);
}

function loadFromCookies(name) {
    var records = [];
    var value = getCookie(name);
    if (!value) return records;
    var values = value.split("&");
    var fields = values.shift().split(",");
    while (values.length > 0) {
        var record = {};
        for (var i = 0; i < fields.length; i++) {
            var field = fields[i];
            var propertyName = field.split(":")[0];
            var propertyType = field.split(":")[1];
            var propertyValue = decodeURIComponent(values.shift());
            switch (propertyType) {
                case "string":
                    break;
                case "number":
                    propertyValue = Number(propertyValue);
                    break;
            }
            record[propertyName] = propertyValue;
        }
        records.push(record);
    }
    return records;
}


///*****************************************************************************\
//  DataCookie
//
//  Представляет собой нупорядоченное множество однотипных объектов
//  с заранне указанными полями. Напоминает таблицу в релеационной
//  базе данных. Первое поле в таблице обязательно должно быть "id"
//  и быть типа nomber.
//\*****************************************************************************/
//
///*class*/ DataCookie = function (/*string*/ name, /*string[]*/ fields) {
//	this.name = name;
//	this.value = getCookie(name);
//
//	this.records = {};
//
//	if (!this.value) return;
//
//	// Получаем записи из куки.
//	var record, id;
//	var values = this.value.split("&");
//	while (values.length > 0) {
//		record = {};
//		for (var i = 0; i < this.fields.length; i++)
//			record[fields[i]] = unescape(values.shift());
//		this.records["_" + record.id] = record;
//	}
//}
//
///**
// * Вставляет запись, если id существует, то запись не замещается.
// */
///*public boolean*/ DataCookie.prototype.insert = function (/*Record*/ record) {
//	if (this.records["_" + record.id] != null) return false;
//	this.records["_" + record.id] = record;
//	return true;
//}
//
///**
// * Вставляет запись, если id существует, то запись замещается.
// */
///*public void*/ DataCookie.prototype.replace = function (/*Record*/ record) {
//	this.records["_" + record.id] = record;
//}
//
///**
// * Обновляет записи. Функция where одновременно выбирает и обновляет поля.
// */
///*public void*/ DataCookie.prototype.update = function (/*Callback*/ where) {
//	for (record in records) where(record);
//}
//
///*public int*/ DataCookie.prototype.getLength = function () {
//	var result = 0;
//	for (record in records) result++;
//	return result;
//}
//
///**
// * Удаляет записи. Возвращается количество удаленных записей,
// * если null - удаляется все.
// */
///*public int*/ DataCookie.prototype.remove = function (/*callback*/ where) {
//	var length = this.getLength();
//	switch (typeof where) {
//		case 'undefined': this.records = {}; break;
//		case 'string':
//		case 'number':    delete this.records["_" + where]; break;
//		case 'function':  for (record in records) if (where(record)) delete this.records["_" + where]; break;
//		default
//			alert('Wrong type!');
//
//	}
//	return length - this.getLength();
//}
//
///**
// * Возврвщает объект объектов, соответствующих условию,
// * проверяемому в функции [where].
// * function where(object record) {
// *     return boolean ;
// * }
// * Если where не указана, возвращаются все записи.
// */
///*public Record{}*/ DataCookie.prototype.select = function (/*callback*/ where) {
//	switch (typeof where) {
//		case 'undefined': return this.records;
//		case 'string':
//		case 'number':    return this.records["_" + where];
//		case 'function':
//			var result = {};
//			for (record in records) if (where(record)) result["_" + record.id] = record;
//		default
//			alert('Wrong type!');
//	}
//}
//
///*public void*/ DataCookie.prototype.set = function () {
//	var value = "";
//
//	for (record in records)
//		for (field in record)
//			value += "&" + escape(field);
//
//	value = this.value.substring(1);
//	setCookie(this.name,  value); /*TODO*/
//}


var WRONG_INDEX = -1;

function getCookie(name/*:String*/)/*:String*/ {
    var result = document.cookie.match(new RegExp(name + "=([^;]*)"));
    if (result) {
        return result[1];
    } else {
        return "";
    }
}

function setCookie(name/*:String*/, value/*:String*/, seconds/*:Number*/,
                   path/*:String*/, domain/*:String*/, secure/*:Boolean*/)/*:Void*/ {
    if (seconds) {
        var expires = new Date;
        expires.setTime(expires.getTime() + seconds * 1000);
    }

    var cookieValue = name + "=" + /*escape(*/value/*)*/ +
            ((expires) ? "; expires=" + expires.toGMTString() : "") +
            ((path) ? "; path=" + path : "") +
            ((domain) ? "; domain=" + domain : "") +
            ((secure) ? "; secure" : "");

    if (cookieValue.length > 4096) {
        throw "Cookie size is more then 4 Kb.";
    }

    document.cookie = cookieValue;
}

function deleteCookie(name/*:String*/, path/*:String*/, domain/*:String*/)/*:Void*/ {
    document.cookie = name + "=" +
            ((path) ? "; path=" + path : "") +
            ((domain) ? "; domain=" + domain : "") +
            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
}
