﻿function Fid(id)
{
    return document.getElementById(id);
}

function Fname(name)
{
    return document.getElementsByName(name);
}

function FtagName(name)
{
    return document.getElementsByTagName(name);
}

function Fempty(v)
{
    if (v != null && (typeof(v) == 'object' || typeof(v) == 'function'))
        return false;
    return (("" == v || undefined == v || null == v) ? true : false);
}

function FhashMap()
{
    this.data = new Object();
}

FhashMap.prototype.get = function(key)
{
    return ((this.data[key] == null || this.data[key] == undefined) ? null :this.data[key]);
}

FhashMap.prototype.put = function(key, value, overlay)
{
    if (overlay != true && this.data[key] != null && this.data[key] !=undefined)
    return false;
    this.data[key] = value;
    return true;
}

FhashMap.prototype.remove = function(key)
{
    if (this.data[key] == null || this.data[key] == undefined)
    return null;
    var tmp = this.data[key];
    delete this.data[key];
    return tmp;
}

FhashMap.prototype.clear = function()
{
    for (key in this.data)
    {
        delete this.data[key];
    }
}

function Ftemplate(tpl, dataObj, unknowns)
{
    this.tpl = tpl;
    this.result = '';
    this.dataObj = dataObj;
    this.unknowns = (Fempty(unknowns) ? 'remove' : unknowns);
    this.blocks = new FhashMap();
    this.vars = new FhashMap();
}

Ftemplate.prototype.toString = function()
{
    this.dataToHTML(this.dataObj);
    return this.result;
}

Ftemplate.prototype.dataToHTML = function(data, node)
{
    for (var key in data)
    {
        var arr = data[key];
        if (arr.constructor == Array)
        {
            if (Fempty(this.blocks.get(key)))
            {
                this.setBlock(Fempty(node) ? '' : node, key, '__' + key + '__');
            }
            var len = arr.length;
            for (i = 0; i < len; i++)
            {
                this.dataToHTML(arr[i], key);
            }
        }
        else
        {
            if (Fempty(node))
            {
                this.setVar(key, arr);
            }
            else
            {
                this.setBlockVar(node, key, arr);
            }
        }
    }
    if (!Fempty(node))
    {
        this.parseBlock(node);
    }
    else
    {
        this.parse();
    }
}

Ftemplate.prototype.setData = function(dataObj)
{
    this.dataObj = dataObj;
}

Ftemplate.prototype.setVar = function(tagName, tagVal, append)
{
    var v = this.vars.get(tagName);
    v = ((!Fempty(v) && (append == true)) ? (v + tagVal): tagVal);
    this.vars.put(tagName, v, true);
}

Ftemplate.prototype.setVars = function(obj, append)
{
    for (key in obj)
    {
        this.setVar(key, obj[key], append);
    }
}

Ftemplate.prototype.clearVar = function(tagName, tagVal)
{
    this.vars.remove(tagName);
}

Ftemplate.prototype.setBlockVar = function(blockName, tagName, tagVal)
{
    this.blocks.get(blockName).vars.put(tagName, tagVal, true);
}

Ftemplate.prototype.setBlockVars = function(blockName, obj)
{
    for (key in obj)
        this.blocks.get(blockName).vars.put(key, obj[key], true);
}

Ftemplate.prototype.clearBlockAllVar = function(blockName)
{
    this.blocks.get(blockName).vars.clear();
}

Ftemplate.prototype.clearBlockVar = function(blockName, tagName)
{
    this.blocks.get(blockName).vars.remove(tagName);
}

Ftemplate.prototype.setBlock = function(parent, blockName, targetVar)
{
    var _parent = Fempty(parent) ? this : this.blocks.get(parent);
    var _tpl = this._getBlock(_parent.tpl, blockName);
    _parent.tpl = this._blockReplace(_parent.tpl, blockName, targetVar);
    this.blocks.put(blockName, 
    {
        'parent': parent, 'targetVar': targetVar, 'tpl': _tpl, 'vars': new
            FhashMap()
    }
    );
    _parent.vars.put(targetVar, "");
}

Ftemplate.prototype._blockReplace = function(tpl, blockName, targetVar)
{
    var _tpl = '';
    var r1 = tpl.match((new RegExp("<!--(\\s)*BEGIN(\\s)+" + blockName + 
        "(\\s)*-->", "")));
    var r2 = tpl.match((new RegExp("<!--(\\s)*END(\\s)+" + blockName + 
        "(\\s)*-->", "")));
    _tpl = tpl.substr(0, r1.index);
    _tpl += '{' + targetVar + '}';
    _tpl += tpl.substr((r2.index + r2[0].length));
    return _tpl;
}

Ftemplate.prototype._getBlock = function(tpl, blockName)
{
    var r1 = tpl.match((new RegExp("<!--(\\s)*BEGIN(\\s)+" + blockName + 
        "(\\s)*-->", "")));
    var r2 = tpl.match((new RegExp("<!--(\\s)*END(\\s)+" + blockName + 
        "(\\s)*-->", "")));
    r1LastIndex = r1.index + r1[0].length;
    return tpl.substr(r1LastIndex, (r2.index - r1LastIndex));
}

Ftemplate.prototype.parse = function()
{
    this.result = this.tpl;
    for (key in this.vars.data)
    {
        this.result = this.result.replace((new RegExp('{' + key + '}', 'ig')),
            this.vars.data[key]);
    }
    return this.result;
}

Ftemplate.prototype.parseBlock = function(tagName, append)
{
    var block = this.blocks.get(tagName);
    var _tpl = block.tpl;
    for (key in block.vars.data)
    {
        _tpl = _tpl.replace((new RegExp('{' + key + '}', 'ig')),
            block.vars.data[key]);
    }
    var _vars = ((Fempty(block.parent)) ? this.vars : this.blocks.get(block.parent).vars);
    var v = _vars.get(block.targetVar);
    append = (Fempty(append) ? true : append);
    v = ((!Fempty(v) && append == true) ? (v + _tpl): _tpl);
    _vars.put(block.targetVar, v, true);
    this.clearBlockAllVar(tagName);
    return v;
}

Ftemplate.prototype.parseBlocks = function(tagName, data, append)
{
    if (!isArray(data))
    {
        if (data == undefined)
            return ;
        this.setBlockVars(tagName, data);
        this.parseBlock(tagName, append);
        return ;
    }
    for (var i = 0; i < data.length; i++)
    {
        if (data[i] == undefined)
            continue;
        this.setBlockVars(tagName, data[i]);
        this.parseBlock(tagName, append);
    }
}

Ftemplate.prototype.show = function(id, append)
{
    var obj = Fid(id);
    if (!Fempty(this.dataObj))
    {
        this.dataToHTML(this.dataObj);
    }
    obj.innerHTML = ((append != true) ? this.result : (obj.innerHTML +
        this.result));
}

