var ApiModule = (function() {
    var core = (function() {
        var module = {
            selectors : {
                html    : 'html',
                head    : 'head',
                script  : 'script'
            },

            types : {
                string : 'string'
            },

            config : {
                require         : '/',
                requireCache    : []
            },

            core : {
                config : function(options) {
                    module.config = $.extend(options, module.config);
                },

                event : function(root, name, target, callback, context) {
                    $(root).on(name, target, function(e){
                        return callback.call(context || this, $(this), e);
                    });
                },

                template : function(name, data, callback, onlyGet) {
                    ApiMicro.template(name, data, callback, onlyGet);
                },

                require : function(names) {
                    var requires = typeof names === module.types.string ? [names] : names, i;

                    for (i in requires) {
                        (function(name) {
                            if (module.config.requireCache.indexOf(name) === -1) {
                                var script      = document.createElement(module.selectors.script);
                                script.src  = module.config.require + name + '.js';

                                $(module.selectors.head).append(script);
                                module.config.requireCache.push(name);
                            }
                        })(requires[i]);
                    }
                },

                root : function(context) {
                    if (context.data.parent && context.data.parent.root) {
                        return '#' + context.data.parent.root;
                    }

                    return module.selectors.html;
                }
            }
        };

        return module.core;
    })();

    var event = (function() {
        var listeners = {}, module = {

            names : {
                onScroll : 'onScroll'
            },

            on : function(name, callback, context) {
                if (!listeners[name]) {
                    listeners[name] = [];
                }

                listeners[name].push([callback, context]);
            },

            ons : function(list, context) {
                var name;

                for (name in list) {
                    if (list.hasOwnProperty(name)) {
                        module.on(name, list[name], context);
                    }
                }
            },

            fire : function(name, data) {
                var i;

                if (listeners[name]) {
                    for (i in listeners[name]) {
                        listeners[name][i][0].call(
                            listeners[name][i][1],
                            data
                        );
                    }
                }
            }
        };

        $(function() {
            $(window).scroll(function() {
                module.fire(module.names.onScroll, {
                    top : $(this).scrollTop()
                });
            });
        });

        return {
            names   : module.names,
            on      : module.on,
            ons     : module.ons,
            fire    : module.fire
        };
    })();

    var create = function(options, root) {
        var module = $.extend({
            events          : {},
            listenersGlobal : {},
            listeners       : {},
            selectors       : {},
            data            : {},
            api             : {},
            core            : core,
            root            : root ? ('id' + new Date().getTime()) : null
        }, options), name;

        for (name in module.api) {
            if (module.api.hasOwnProperty(name)) {
                (function(name, callback) {
                    module.api[name] = function() {
                        return callback.apply(module, arguments);
                    };
                })(name, module.api[name]);
            }
        }

        $(function(){
            for(var e in module.events) {
                if(module.events.hasOwnProperty(e)) {
                    (function(e) {
                        core.event(
                            core.root(module),
                            e.substr(0, e.indexOf(' ')),
                            (module.root ? '#' + module.root + ' ' : '') + e.substr(e.indexOf(' ')+1),
                            module.listeners[module.events[e]],
                            module
                        );
                    })(e);
                }
            }

            for(var e in module.listenersGlobal) {
                if(module.listenersGlobal.hasOwnProperty(e)) {
                    (function(e) {
                        event.on(
                            e,
                            module.listenersGlobal[e],
                            module
                        );
                    })(e);
                }
            }

            if (module.listeners.onInit) {
                module.listeners.onInit.call(module);
            }
        });

        return module.api;
    };

    var prepare = function(options) {
        return function(data, root) {
            var extend = $.extend(true, {}, options), i;

            for (i in data) {
                if (data.hasOwnProperty(i)) {
                    if (!extend.data) {
                        extend.data = {};
                    }
                    
                    extend.data[i] = data[i];
                }
            }

            return create(extend, root);
        }
    };

    return {
        core    : core,
        event   : event,
        create  : create,
        prepare : prepare
    };
})();
