function checkValue(o, d) {
    "use strict";
    return o || d;
}

function getTemplate(id) {
    "use strict";
    var ret = "";
    ret = document.getElementById(id);
    if (ret) {
        ret = ret.innerHTML;
    } else {
        ret = "";
    }
    return ret;
}

Date.prototype.format = function (format) {
    "use strict";
    var k = null,
        o = {
            "M+": this.getMonth() + 1, //month
            "d+": this.getDate(),    //day
            "h+": this.getHours(),   //hour
            "m+": this.getMinutes(), //minute
            "s+": this.getSeconds(), //second
            "q+": Math.floor((this.getMonth() + 3) / 3),  //quarter
            "S": this.getMilliseconds() //millisecond
        };

    if (/(y+)/.test(format)) {
        format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    }
    for (k in o) {
        if (new RegExp("(" + k + ")").test(format)) {
            format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
        }
    }
    return format;
};

function isEspecificObject(o, t) {
    "use strict";
    return o instanceof t;
}

function isDate(o) {
    "use strict";
    return isEspecificObject(o, Date);
}

function isString(o) {
    "use strict";
    return typeof (o) === "string";
}

function isObject(o) {
    "use strict";
    return isEspecificObject(o, Object);
}

function isFunction(o) {
    "use strict";
    return isEspecificObject(o, Function);
}

function isUndefined(o) {
    "use strict";
    return o === null || typeof (o) === "undefined";
}

function isArray(o) {
    "use strict";
    return isEspecificObject(o, Array);
}

String.prototype.startWith = function (compare, isSensitive) {
    applySensitive.apply(this, arguments);
    return this.indexOf(compare) === 0;
};

String.prototype.endWith = function (compare, isSensitive) {
    applySensitive.apply(this, arguments);
    return this.lastIndexOf(compare) === this.length - 1;
};

String.prototype.endWith = function (compare, isSensitive) {
    applySensitive.apply(this, arguments);
    return this.lastIndexOf(compare) > -1;
};

function applySensitive(compare, isSensitive) {
    var str = this,
        comp = compare;

    if (isSensitive) {
        str.toUpperCase();
        comp.toUpperCase();
    }
}

/*
@param obj objeto da api google maps
@param handlers lista do objeto Handler
@param ret objeto de retorno para a função
*/
function setEventHandler(obj, handlers, ret) {
    for (var i = 0; i < handlers.length; i++) {
        mapsHandler(obj, handlers[i], ret);
    }
}

function mapsHandler(obj, handler, ret) {
    google.maps.event.clearListeners(obj, handler.eventName);
    if (isFunction(handler.callback)) {
        google.maps.event.addListener(obj, handler.eventName, function (evt) {
            handler.callback(evt, checkValue(ret, this));
        });
    }
}

function Handler(o) {
    "use strict";
    if (!isEspecificObject(this, Handler)) {
        return new Handler(o);
    }
    var mSelf = this;
    mSelf.eventName = o.eventName;
    mSelf.callback = o.callback;
}

// clonagem gerérica de um objeto para outro
function clonarDePara(de, mapListFn) {
    // cria as variáveis
    // se for um objeto que contém uma lista já deixa instanciado
    var ret = new de.constructor(),
            jsonValues = null,
            objValues = null;

    if (isFunction(mapListFn)) {
        // se uma função de mapeamento foi passada
        // o objeto contem uma propriedade Lista com objetos
        // pegamos a lista de objetos através do método salvar
        jsonValues = de.salvar();
        // após realiza-se um mapeamento através da função
        objValues = ko.utils.arrayMap(jsonValues, mapListFn);
        // joga todos os objetos mapeados dentro da lista do objeto final
        ret.Lista.push.apply(ret.Lista, objValues);
    } else {
        // se a clonagem for de um objeto sem lista
        // pega-se os valores em notação json
        jsonValues = de.clone();
        // cria-se uma nova instância com os valorem em json
        ret = new de.constructor(jsonValues);
    }

    // retorna-se o objeto clonado sem referências para o objeto raiz
    return ret;
}

function koUnwrap(o) {
    "use strict";
    return ko.utils.unwrapObservable(o);
}

/*
*
* Função para mostrar opção do menu
* Se for clicada na opção já mostrada fecha a mesma
*
*/
function toggle(toShow) {
    "use strict";
    var mSelf = this,
        wasVisible = false,
        show = false,
        regex = new RegExp("Toggle$");

    function hide(o) {
        var value = koUnwrap(o),
            visible = null;

        if (isFunction(value.toggleIsVisible)) {
            visible = value.toggleIsVisible();
        }

        if (isFunction(value.hide)) {
            value.hide();
        }

        return visible;
    }

    for (var p in mSelf) {
        if (regex.test(p)) {
            wasVisible = mSelf[p](false);
            show = p.indexOf(toShow) > -1;
            show &= wasVisible;
        }

    }
    if (show) {
        mSelf[toShow]();
    }
}