var _ = require('lodash');
var util = require('util');
var CodeGen = require('./codeGen');
var cheerio = require('cheerio');

function JQfy() {
    var jqfy = this;

    jqfy.compile = function (html, opts) {
        opts = _.extend({
            returnType: 'contents', // html, root, contents [children is deprecated]
            trim: true, // true, false
            comment: true, // true, false
            script: false // false TODO not supported yet
        }, opts);
        if (opts.returnType == 'children') {
            opts.returnType = 'contents';
        }
        var name = CodeGen.normalizeName(opts.name);
        var cg = new CodeGen();
        var commentIndent = 0;
        var counts = {};

        function generate(node, parentCtx) {
            if (parentCtx === undefined) {
                parentCtx = {};
            }
            var ctx = {};
            var variable;
            ctx.pre = parentCtx.pre;
            if (node.type == 'root') {
                variable = '$root';
            }
            if (node.type == 'tag') {
                cg.raw();
                if (counts[node.name] === undefined) {
                    counts[node.name] = 1;
                }
                variable = '$' + node.name + counts[node.name];
                counts[node.name] += 1;
                cg.raw(util.format("var %s = $('<%s/>')", variable, node.name));
                cg.incIndent();
                if (node.attribs.id) {
                    cg.raw(util.format('.attr(%s, %s)', JSON.stringify('id'), JSON.stringify(node.attribs.id)));
                }

                if (node.attribs['class']) {
                    cg.raw(util.format('.addClass(%s)', JSON.stringify(node.attribs['class'])));
                }

                Object.keys(node.attribs).forEach(function (a) {
                    var v = node.attribs[a];
                    if (a == 'class') {
                        return;
                    }
                    if (a == 'id') {
                        return;
                    }
                    cg.raw(util.format('.attr(%s, %s)', JSON.stringify(a), JSON.stringify(v)));
                });
                cg.raw(util.format('.appendTo(%s);', parentCtx.parent));
                cg.decIndent();
                if (node.name == 'pre') {
                    ctx.pre = true;
                }
            }
            if (node.type == 'text') {
                var text = node.data;

                if (opts.trim && !ctx.pre) {
                    text = text.trim();
                }

                if (text) {
                    var value = JSON.stringify(text);
                    cg.raw(util.format('%s.append(document.createTextNode(%s));', parentCtx.parent, value));
                }
            }
            if (node.type == 'comment') {
                if (opts.comment) {
                    cg.raw(util.format('%s.append(document.createComment(%s));', parentCtx.parent, JSON.stringify(node.data)));
                }
            }
            if (node.type == 'script') {
                return;
            }
            ctx.parent = variable;
            if (node.children) {
                commentIndent++;
                node.children.forEach(function (child) {
                    generate(child, ctx);
                });
                cg.comment(new Array(commentIndent).join(' ') + 'end ' + variable);
                commentIndent--;
            }

        }

        var ch = cheerio.load(html);

        cg.functionStart(name, ['data', 'opts']);
        cg.comment('generated by jQfy');

        cg.raw('opts = $.extend({},opts);');

        cg.raw("var $root = $('<div/>');");
        generate(ch._root);

        var d = "";
        switch (opts.returnType) {
            case 'html':
                d = "return $root.html();\n";
                break;
            case 'root':
                d = "return $root;\n";
                break;
            case 'contents':
                d = "return $root.contents();\n";
                break;
            default :
                d = "return $root.contents();\n";
        }

        var c = "switch (opts.returnType) {\n" +
            "    case 'html':\n" +
            "        return $root.html();\n" +
            "    case 'root':\n" +
            "        return $root;\n" +
            "    case 'contents':\n" +
            "    case 'children': // will be removed in version 2.*\n" + // TODO remove in version 2.*
            "        return $root.contents();\n" +
            "    default :\n" +
            "        " + d +
            "}";
        cg.raw(c);
        cg.functionEnd();
        return cg.getCode();
    };


    var memory = [];
    jqfy.append = function (html, opts) {
        if (opts.name == undefined) {
            throw new Error('Name is required');
        }
        if (typeof opts.name == 'string') {
            opts.name = [opts.name];
        }
        opts.name.unshift('templates');
        memory.push({
            html: html,
            opts: opts,
            name: opts.name
        });
    };
    jqfy.getCode = function (name) {
        var output = new CodeGen();
        var nameParam = '';
        if (name) {
            nameParam = JSON.stringify(name) + ', ';
        }
        var moduleName = 'templates';
        if (name) {
            moduleName = name;
        }

        var umdBegin = "(function(root, factory) {\n" +
            output.getIndent(1) + "if (typeof define === 'function' && define.amd) {\n" +
            output.getIndent(2) + "define(" + nameParam + "['jquery'], factory);\n" +
            output.getIndent(1) + "} else if (typeof exports === 'object') {\n" +
            output.getIndent(2) + "module.exports = factory(require('jquery'));\n" +
            output.getIndent(1) + "} else {\n" +
            output.getIndent(2) + "root." + moduleName + " = factory(jQuery);\n" +
            output.getIndent(1) + "}\n" +
            "})(this, function($) {";
        var umdEnd = "});";
        output.raw(umdBegin);
        output.incIndent();
        output.raw('var templates = {};');
        var paths = {'templates': true};
        //var memory = _.sortBy(memory, 'name');
        memory.forEach(function (item) {
            var p = [];
            item.opts.name.forEach(function (n, i) {
                p.push(n);
                var v = CodeGen.normalizeName(p);
                if (paths[v]) {
                    return;
                }
                paths[v] = true;
                if (i + 1 == item.opts.name.length) {
                    return;
                }

                output.raw(v + ' = {};');
            });
            output.raw(jqfy.compile(item.html, item.opts));
        });

        output.raw('return templates;');
        output.decIndent();
        output.raw(umdEnd);
        return output.getCode();
    };

    jqfy.flush = function () {
        memory = [];
    };
}

module.exports = new JQfy();
@@ -6176,14 +6176,8 @@
     
-//var 
 memo

fix some bugs