
(function () {

    /* interface */

    function Uai() {
        init.apply(this, arguments);
    }

    Uai.prototype = {
        isOs                 : isOs,
        isBrowser            : isBrowser,
        getOsIdentifier      : getOsIdentifier,
        getBrowserIdentifier : getBrowserIdentifier
    };

    window.Uai = Uai;


    /* implement */

    var OS_DEFINE_LIST = {
        win7          : new Agent('win',     '7',           8,    null),
        winVista      : new Agent('win',     'vista',       7,    null),
        winServer2003 : new Agent('win',     'server_2003', 6,    null),
        winXp         : new Agent('win',     'xp',          5,    null),
        winMe         : new Agent('win',     'me',          4,    null),
        win2000       : new Agent('win',     '2000',        3,    null),
        win98         : new Agent('win',     '98',          2,    null),
        winNt         : new Agent('win',     'nt',          1,    null),
        win95         : new Agent('win',     'win95',       0,    null),
        mac           : new Agent('mac',     null,          null, null),
        linux         : new Agent('linux',   null,          null, null),
        bds           : new Agent('bds',     null,          null, null),
        solaris       : new Agent('solaris', null,          null, null),
        iPhone        : new Agent('iphone',  null,          null, ['smart_phone']),
        iPod          : new Agent('ipod',    null,          null, ['smart_phone']),
        iPad          : new Agent('ipad',    null,          null, ['tablet']),
        android       : new Agent('android', null,          null, ['smart_phone']),
        unknown       : new Agent('unknown', null,          null, null)
    };

    var BROWSER_DEFINE_LIST = {
        opera   : new Agent('opera',   null, null, null),
        ie6     : new Agent('ie',      '6',  6,    null),
        ie7     : new Agent('ie',      '7',  7,    null),
        ie8     : new Agent('ie',      '8',  8,    null),
        ie9     : new Agent('ie',      '9',  9,    null),
        chrome  : new Agent('chrome',  null, null, null),
        firefox : new Agent('firefox', null, null, null),
        safari  : new Agent('safari',  null, null, null),
        unknown : new Agent('unknown', null, null, null)
    };
    
    var OPERATOR = {
        gt  : 'gt',
        lt  : 'lt',
        gte : 'gte',
        lte : 'lte'
    };

    var SEPARATOR = '_';

    var os;

    var br;

    function init() {
        var uastr = window.navigator.userAgent;
        os = judgeOs(uastr);
        os.identifier = generateIdentifier(os, OS_DEFINE_LIST);
        br = judgeBrowser(uastr);
        br.identifier = generateIdentifier(br, BROWSER_DEFINE_LIST);
    }

    function isOs(identifier) {
        return (os.identifier.indexOf(identifier) != -1);
    }

    function isBrowser(identifier) {
        return (br.identifier.indexOf(identifier) != -1);
    }

    function getOsIdentifier() {
        return os.identifier;
    }

    function getBrowserIdentifier() {
        return br.identifier;
    }

    function judgeOs(uastr) {
        if      (uastr.match(/iPhone/))                    return OS_DEFINE_LIST.iPhone;
        else if (uastr.match(/iPod/))                      return OS_DEFINE_LIST.iPod;
        else if (uastr.match(/iPad/))                      return OS_DEFINE_LIST.iPad;
        else if (uastr.match(/Android/))                   return OS_DEFINE_LIST.android;
        else if (uastr.match(/Win(dows )?NT 6\.1/))        return OS_DEFINE_LIST.win7;
        else if (uastr.match(/Win(dows )?NT 6\.0/))        return OS_DEFINE_LIST.winVista;
        else if (uastr.match(/Win(dows )?NT 5\.2/))        return OS_DEFINE_LIST.winServer2003;
        else if (uastr.match(/Win(dows )?(NT 5\.1|XP)/))   return OS_DEFINE_LIST.winXp;
        else if (uastr.match(/Win(dows)? (9x 4\.90|ME)/))  return OS_DEFINE_LIST.win2000;
        else if (uastr.match(/Win(dows )?(NT 5\.0|2000)/)) return OS_DEFINE_LIST.winMe;
        else if (uastr.match(/Win(dows )?98/))             return OS_DEFINE_LIST.win98;
        else if (uastr.match(/Win(dows )?NT( 4\.0)?/))     return OS_DEFINE_LIST.winNt;
        else if (uastr.match(/Win(dows )?95/))             return OS_DEFINE_LIST.win95;
        else if (uastr.match(/Mac|PPC/))                   return OS_DEFINE_LIST.mac;
        else if (uastr.match(/Linux/))                     return OS_DEFINE_LIST.linux;
        else if (uastr.match(/(Free|Net|Open)BSD/))        return OS_DEFINE_LIST.bsd;
        else if (uastr.match(/SunOS/))                     return OS_DEFINE_LIST.solaris;
        else                                               return OS_DEFINE_LIST.unknown;
    }

    function judgeBrowser(uastr) {
        if      (uastr.match(/Opera/))    return BROWSER_DEFINE_LIST.opera;
        else if (uastr.match(/MSIE 6\./)) return BROWSER_DEFINE_LIST.ie6;
        else if (uastr.match(/MSIE 7\./)) return BROWSER_DEFINE_LIST.ie7;
        else if (uastr.match(/MSIE 8\./)) return BROWSER_DEFINE_LIST.ie8;
        else if (uastr.match(/MSIE 9\./)) return BROWSER_DEFINE_LIST.ie9;
        else if (uastr.match(/Chrome/))   return BROWSER_DEFINE_LIST.chrome;
        else if (uastr.match(/Firefox/))  return BROWSER_DEFINE_LIST.firefox;
        else if (uastr.match(/Safari/))   return BROWSER_DEFINE_LIST.safari;
        else                              return BROWSER_DEFINE_LIST.unknown;
    }

    function generateIdentifier(agent, agentDefineList) {
        var identifier = [];
        identifier.push(agent.type);
        if (agent.varsionName) identifier.push(agent.type + SEPARATOR + agent.varsionName);
        if (agent.groups instanceof Array) identifier = identifier.concat(agent.groups);
        var sameTypeAgents = findSameTypeAgents(agentDefineList, agent.type);
        if (sameTypeAgents.length <= 1) return identifier;
        for (var key in sameTypeAgents) {
            var elem = sameTypeAgents[key];
            if (elem.varsionNum < agent.varsionNum)
                identifier.push(agent.type + SEPARATOR + elem.varsionName + SEPARATOR + OPERATOR.gt);
            if (elem.varsionNum <= agent.varsionNum)
                identifier.push(agent.type + SEPARATOR + elem.varsionName + SEPARATOR + OPERATOR.gte);
            if (elem.varsionNum >= agent.varsionNum)
                identifier.push(agent.type + SEPARATOR + elem.varsionName + SEPARATOR + OPERATOR.lte);
            if (elem.varsionNum > agent.varsionNum)
                identifier.push(agent.type + SEPARATOR + elem.varsionName + SEPARATOR + OPERATOR.lt);
        }
        return identifier;
    }

    function findSameTypeAgents(agentDefineList, type) {
        var sameTypeAgents = [];
        for (var key in agentDefineList) {
            var elem = agentDefineList[key];
            if (elem.type === type) sameTypeAgents.push(elem);
        }
        return sameTypeAgents;
   }

    function Agent(type, varsionName, varsionNum, groups) {
        this.type = type;
        this.varsionName = varsionName;
        this.varsionNum = varsionNum;
        this.groups = groups;
        this.identifier = [];
    }

})();


