/*global describe it before after bar = */

"use client";

require(["lib/architect/architect", "lib/chai/chai"], 
  function (architect, chai, baseProc) {
    var expect = chai.expect;
    
    expect.setupArchitectTest([
        {
            packagePath: "plugins/c9.core/c9",
            startdate: new Date(),
            debug: true,
            hosted: true,
            local: false,
            davPrefix: "/"
        },
        
        "plugins/c9.core/ext",
        "plugins/c9.core/http-xhr",
        "plugins/c9.core/util",
        "plugins/c9.ide.ui/lib_apf",
        {
            packagePath: "plugins/c9.core/settings",
            testing: true
        },
        "plugins/c9.core/api.js",
        {
            packagePath: "plugins/c9.ide.ui/ui",
            staticPrefix: "plugins/c9.ide.ui"
        },
        "plugins/c9.ide.editors/document",
        "plugins/c9.ide.editors/undomanager",
        {
            packagePath: "plugins/c9.ide.editors/editors",
            defaultEditor: "texteditor"
        },
        "plugins/c9.ide.editors/editor",
        "plugins/c9.ide.editors/tabmanager",
        "plugins/c9.ide.ui/focus",
        "plugins/c9.ide.editors/pane",
        "plugins/c9.ide.editors/tab",
        "plugins/c9.ide.editors/texteditor",
        "plugins/c9.ide.editors/timeview",
        "plugins/c9.ide.editors/imgview",
        {
            packagePath: "plugins/c9.vfs.client/vfs_client"
        },
        "plugins/c9.vfs.client/endpoint",
        "plugins/c9.ide.auth/auth",
        {
            packagePath: "plugins/c9.fs/fs",
            baseProc: baseProc
        },
        "plugins/c9.fs/fs.cache.xml",
        
        // Mock plugins
        {
            consumes: ["apf", "ui", "Plugin"],
            provides: [
                "commands", "menus", "commands", "layout", "watcher", "proc",
                "save", "anims", "clipboard", "dialog.alert", "auth.bootstrap",
                "info", "dialog.error"
            ],
            setup: expect.html.mocked
        },
        {
            consumes: ["tabManager", "ui", "fs.cache", "fs"],
            provides: [],
            setup: main
        }
    ], architect);
    
    function main(options, imports, register) {
        var tabs = imports.tabManager;
        var fs = imports.fs;
        
        function countEvents(count, expected, done) {
            if (count == expected) 
                done();
            else
                throw new Error("Wrong Event Count: "
                    + count + " of " + expected);
        }
        
        expect.html.setConstructor(function(tab) {
            if (typeof tab == "object")
                return tab.pane.aml.getPage("editor::" + tab.editorType).$ext;
        });
        
        describe('tabs', function() {
            this.timeout(20000);
            
            before(function(done) {
                apf.config.setProperty("allow-select", false);
                apf.config.setProperty("allow-blur", false);
                
                bar.$ext.style.background = "rgba(220, 220, 220, 0.93)";
                bar.$ext.style.position = "fixed";
                bar.$ext.style.left = "20px";
                bar.$ext.style.right = "20px";
                bar.$ext.style.bottom = "20px";
                bar.$ext.style.height = "33%";
      
                document.body.style.marginBottom = "33%";
                
                tabs.once("ready", function(){
                    tabs.getPanes()[0].focus();
                    done();
                });
            });
            
            var text;
            describe("open(), openFile(), openEditor() and reload()", function(){
                it('should open a pane from a path', function(done) {
                    var vpath = "/file.txt";
                    tabs.openFile(vpath, function(err, tab) {
                        expect(tabs.getTabs()).length(1);
                        
                        expect(tabs.focussedTab)
                            .to.exist
                            .property("path").to.equal(vpath);
                        expect(tab.title).to.equal(vpath.substr(1));
                        
                        fs.readFile(vpath, "utf8", function(err, data) {
                            text = data;
                            expect(tab.document.value).to.equal(data);
                            done();
                        });
                    });
                });
                it('should open a pane with just an editor', function(done) {
                    tabs.openEditor("timeview", function(err, tab) {
                        expect(tabs.getTabs()).length(2);
                        
                        expect(tabs.focussedTab)
                            .to.exist
                            .to.not.equal(tab);
                            //.property("path").to.equal(vpath);
                        done();
                    });
                });
                it('should handle multiple docs on the same editor well', function(done) {
                    var vpath = "/listing.json";
                    tabs.open({
                        path: vpath,
                        active: true
                    }, function(err, tab) {
                        expect(tabs.getTabs()).length(3);
                        expect(tab.title).to.equal(vpath.substr(1));
                        
                        expect(tabs.focussedTab)
                            .to.exist
                            .property("path").to.equal(vpath);
                            
                        fs.readFile(vpath, "utf8", function(err, data) {
                            expect(tab.document.value).to.equal(data);
                            
                            tabs.activateTab("/file.txt");
                            expect(tabs.focussedTab.document.value)
                                .to.equal(text);
                            
                            tabs.openEditor("timeview", function(err, tab) {
                                expect(tabs.getTabs()).length(4);
                                
                                tabs.activateTab(tab);
                                expect(tabs.focussedTab)
                                    .to.exist
                                    .to.equal(tab);
                                
                                tabs.activateTab(tabs.getTabs()[1]);
                                expect.html(tabs.focussedTab).is.visible;
                                done();
                            });
                        });
                    });
                });
                it('should reload the contents of an editor on a tab', function(done) {
                    var tab = tabs.findTab("/file.txt");
                    tabs.activateTab(tab);
                    tab.document.value = "Testing";
                    tabs.reload(tab, function(err) {
                        if (err) throw err.message;
                        expect(tab.document.value).to.equal(text);
                        done();
                    });
                });
                it('should open a non-existing file with empty content passed as value', function(done) {
                    var vpath = "/Untitled1";
                    tabs.open({
                        path: vpath,
                        value: "",
                        active: true,
                    }, function(err, tab) {
                        expect(tabs.getTabs()).length(5);
                        expect(tab.title).to.equal(vpath.substr(1));
                        expect(tabs.focussedTab)
                            .to.exist
                            .property("path").to.equal(vpath);
                        
                        expect(tabs.focussedTab.document.value).to.equal("");
                        
                        done();
                    });
                });
                it('should open a non-existing file with set content passed as value', function(done) {
                    var vpath = "/Untitled2";
                    var text = "This is a test";
                    tabs.open({
                        path: vpath,
                        value: text,
                        active: true,
                    }, function(err, tab) {
                        expect(tabs.getTabs()).length(6);
                        expect(tab.title).to.equal(vpath.substr(1));
                        expect(tabs.focussedTab)
                            .to.exist
                            .property("path").to.equal(vpath);
                        
                        expect(tabs.focussedTab.document.value)
                            .to.equal(text);
                        
                        done();
                    });
                });
            });

            describe("File system rename hooks - change open tab paths", function(){
                it('should rename a file  - change page path', function(done) {
                    var vpath = "/dir/stuff.json";
                    var newVpath = "/dir/stuff2.json";
                    tabs.openFile(vpath, function(err, tab) {
                        expect(tab.path).to.equal(vpath);
                        expect(tab.title).to.equal("stuff.json");
                        
                        fs.rename(vpath, newVpath, function(err) {
                            if (err)
                                throw err;
                            expect(tab.path).to.equal(newVpath);
                            tab.unload();
                            fs.rename(newVpath, vpath, function (err) {
                                if (err)
                                    throw err;
                                done();
                            });
                        });
                    });
                });

                it('should rename a directory  - change tab path', function(done) {
                    var vpath = "/dir/stuff.json";
                    fs.rmdir("/dir2", { recursive: true }, function(){
                        tabs.openFile(vpath, function(err, tab) {
                            expect(tab.path).to.equal(vpath);
                            expect(tab.title).to.equal("stuff.json");
                            
                            fs.rename("/dir", "/dir2", function(err) {
                                if (err)
                                    throw err;
                                expect(tab.path).to.equal("/dir2/stuff.json");
                                expect(tab.title).to.equal("stuff.json");
                                tab.unload();
                                fs.rename("/dir2", "/dir", function (err) {
                                    if (err)
                                        throw err;
                                    done();
                                });
                            });
                        });
                    });
                });
            });

            describe("getTabs(), getPanes()", function(){
                it('should return a list containing all the pages', function(done) {
                    expect(tabs.getTabs()).length.gt(4);
                    done();
                });
                it('should return a list containing all the tabs', function(done) {
                    expect(tabs.getPanes()).length(1);
                    done();
                });
                it('should return an editor of a tab', function(done) {
                    expect(tabs.findTab("/file.txt").editor)
                        .property("type").to.equal("texteditor");
                    done();
                });
            });
            describe("switchEditor()", function(){
                it('should switch to another editor for the selected tab', function(done) {
                    var tab = tabs.focusTab("/file.txt");
                    tab.switchEditor("imgview", function(){
                        expect(tabs.focussedTab.editor)
                            .property("type").to.equal("imgview");
                        tab.switchEditor("texteditor", function(){
                            expect(tabs.focussedTab.document.value).to.equal(text);
                            done();
                        });
                    });
                });
                it('should switch to another editor for a given tab (not selected)', function(done) {
                    var tab = tabs.findTab("/listing.json");
                    tab.switchEditor("imgview", function(){
                        expect(tab.editor)
                            .property("type").to.equal("imgview");
                        tab.switchEditor("texteditor", function(){
                            expect(tabs.focussedTab.document.value).to.equal(text);
                            done();
                        });
                    });
                });
            });

            describe("clear(), getState() and setState()", function(){
                var state, info = {};
                it('should retrieve the state', function(done) {
                    state = tabs.getState();
                    info.pages = tabs.getTabs().map(function(tab) {
                        return tab.path || tab.id;
                    });
                    done();
                });
                it('should clear all tabs and pages', function(done) {
                    var count = 0, expected = 0;
                    tabs.getTabs().forEach(function(tab) {
                        expected += 2;
                        tab.on("unload", function(){
                            count++;
                        });
                        tab.document.on("unload", function(){
                            count++;
                        });
                    });
                    
                    tabs.getPanes()[0];
                    tabs.clear();
                    expect(tabs.getTabs(), "pages").length(0);
                    expect(tabs.getPanes(), "tabManager").length(0);

                    countEvents(count, expected, done);
                });
                it('should restore the state', function(done) {
                    tabs.setState(state, false, function(err) {
                        if (err) throw err.message;
                    });
                    var l = info.pages.length;
                    expect(tabs.getTabs()).length(l);
                    expect(tabs.getPanes()[0].getTabs()).length(l);
                    expect(tabs.focussedTab.pane.getTabs()).length(l);
                    expect(tabs.getTabs()[2].title).to.equal("listing.json");
                    expect(tabs.getTabs().map(function(tab) {
                        return tab.path || tab.id;
                    })).to.deep.equal(info.pages);
                    done();
                });
            });
//            describe("pauseTabResize() and continueTabResize()", function(){
//                it('should stop resizing of tabs', function(done) {
//                    var pane = tabs.focussedTab.pane;
//                    var w = pane.aml.getWidth();
//                    var pw = pane.getTab().aml.getWidth();
//                    tabs.pauseTabResize();
//                    pane.$ext.style.width = (200) + "px";
//                    expect(pane.getTab().aml.getWidth()).to.equal(pw);
//                    done();
//                });
//                it('should restore resizing of tabs', function(done) {
//                    done();
//                });
//            });

            describe("vsplit(), hsplit(), removeTab()", function(){
                it('should split a pane vertically, making the existing pane the top one', function(done) {
                    var pane = tabs.focussedTab.pane;
                    var btmtab = pane.vsplit(true);
                    expect(pane.aml.getTop()).lt(btmtab.aml.getTop());
                    tabs.focussedTab.attachTo(btmtab);
                    tabs.on("tabAfterActivate", function c1(){
                        expect(tabs.focussedTab.title).to.equal("file.txt");
                        expect(tabs.focussedTab.document.value).to.equal(text);
                        expect(tabs.focussedTab.editor).to.equal(tabs.focussedTab.pane.aml.getPage("editor::texteditor").editor);
                        tabs.off("tabAfterActivate", c1);
                        done();
                    });
                    tabs.focusTab("/file.txt");
                });
                it('should remove the bottom pane from a vertical split', function(done) {
                    var pane = tabs.getPanes()[1];
                    var tab = pane.getTab();
                    pane.unload();
                    expect(tabs.getPanes()).length(1);
                    expect(tabs.getTabs()).length(6);
                    tabs.focusTab(tab);
                    expect(tab.editor.name).to.equal("texteditor1");
                    expect.html(tab.pane.aml.getPage("editor::texteditor").$ext).visible;
                    done();
                });
                it('should split a pane vertically, making the existing pane the bottom one', function(done) {
                    var pane = tabs.focussedTab.pane;
                    var toptab = pane.vsplit();
                    expect(toptab.aml.getTop()).lt(pane.aml.getTop());
                    tabs.focussedTab.attachTo(toptab);
                    tabs.on("tabAfterActivate", function c1(){
                        expect(tabs.focussedTab.title).to.equal("file.txt");
                        expect(tabs.focussedTab.document.value).to.equal(text);
                        expect(tabs.focussedTab.editor).to.equal(tabs.focussedTab.pane.aml.getPage("editor::texteditor").editor);
                        tabs.off("tabAfterActivate", c1);
                        done();
                    });
                    tabs.focusTab("/file.txt");
                });
                it('should remove the top pane from a vertical split', function(done) {
                    var pane = tabs.getPanes()[0];
                    var tab = pane.getTab();
                    pane.unload();
                    expect(tabs.getPanes()).length(1);
                    expect(tabs.getTabs()).length(6);
                    tabs.focusTab(tab);
                    expect(tab.editor.name).to.equal("texteditor3");
                    expect(tab.pane.aml.getPage("editor::texteditor").$ext.style.display).to.not.equal("none");
                    done();
                });
                it('should split a pane horizontally, making the existing pane the left one', function(done) {
                    var pane = tabs.focussedTab.pane;
                    var righttab = pane.hsplit(true);
                    expect(pane.aml.getLeft()).lt(righttab.aml.getLeft());
                    tabs.focussedTab.attachTo(righttab);
                    tabs.focusTab("/file.txt");
                    expect(tabs.focussedTab.title).to.equal("file.txt");
                    expect(tabs.focussedTab.document.value).to.equal(text);
                    expect(tabs.focussedTab.editor).to.equal(tabs.focussedTab.pane.aml.getPage("editor::texteditor").editor);
                    done();
                });
                it('should remove the left pane from a horizontal split', function(done) {
                    var pane = tabs.getPanes()[0];
                    var tab = tabs.getPanes()[1].getTab();
                    pane.unload();
                    expect(tabs.getPanes()).length(1);
                    expect(tabs.getTabs()).length(6);
                    tabs.focusTab(tab);
                    expect(tab.editor.name).to.equal("texteditor4");
                    expect(tab.pane.aml.getPage("editor::texteditor").$ext.style.display).to.not.equal("none");
                    done();
                });
                it('should split a pane horizontally, making the existing pane the right one', function(done) {
                    var pane = tabs.focussedTab.pane;
                    var lefttab = pane.hsplit();
                    expect(lefttab.aml.getLeft()).lt(pane.aml.getLeft());
                    tabs.focussedTab.attachTo(lefttab);
                    tabs.focusTab("/file.txt");
                    expect(tabs.focussedTab.title).to.equal("file.txt");
                    expect(tabs.focussedTab.document.value).to.equal(text);
                    expect(tabs.focussedTab.editor).to.equal(tabs.focussedTab.pane.aml.getPage("editor::texteditor").editor);
                    done();
                });
                it('should remove the right pane from a horizontal split', function(done) {
                    var pane = tabs.getPanes()[1];
                    var tab = pane.getTab();
                    pane.unload();
                    expect(tabs.getPanes()).length(1);
                    expect(tabs.getTabs()).length(6);
                    tabs.focusTab(tab);
                    expect(tab.editor.name).to.equal("texteditor4");
                    expect(tab.pane.aml.getPage("editor::texteditor").$ext.style.display).to.not.equal("none");
                    done();
                });
                it('should be able to create a complex 5 pane layout', function(done) {
                    var first = tabs.getPanes()[0];
                    var right = first.hsplit(true);
                    right.width = "20%";
                    
                    var other = first.vsplit();
                    other.hsplit();
                    first.hsplit();
                
                    var pages = tabs.getTabs();
                    expect(pages).length(6);
                    tabs.getPanes().forEach(function(pane) {
                        pages.pop().attachTo(pane);
                    });
                    
                    expect(tabs.getPanes()).length(5);
                    expect(tabs.getTabs()).length(6);
                    
                    done();
                });
                it('should propertly serialize and deserialize', function(done) {
                    var cstate = tabs.getState();
                    var state = tabs.getState();
                    tabs.clear();
                    expect(tabs.getPanes()).length(0);
                    expect(tabs.getTabs()).length(0);
                    apf.z = 1;
                    tabs.setState(state, function(err) {
                        if (err) throw err.message;
                    });
                    console.log(cstate, tabs.getState());
                    expect(cstate).to.deep.equal(tabs.getState());
                    
                    expect(tabs.getPanes()).length(5);
                    expect(tabs.getTabs()).length(6);
                    
                    //Loop through state to check all the widths/heights
                    
//                    (function recur(parent, list) {
//                        list.forEach(function(state) {
//                            var p;
//                            
//                            if (state.type == "pane") {
//                                p = createPane(state).aml;
//                                parent.appendChild(p);
//                            }
//                            else if (state.type == "hsplitbox" || state.type == "vsplitbox") {
//                                p = parent.appendChild(new ui[state.type]({
//                                    splitter : true,
//                                    padding  : 3,
//                                    width    : state.width,
//                                    height   : state.height
//                                }));
//                            }
//                            else if (state.type == "tab") {
//                                var tab = findTab(state.id);
//                                if (!tab) {
//                                    state.pane = parent.cloud9pane;
//                                    state.init = init;
//                                    
//                                    open(state, function(err, tab) {
//                                        callback(err, tab);
//                                    });
//                                }
//                                else {
//                                    tab.attachTo(parent);
//                                }
//                                return;
//                            }
//                            recur(p, state.nodes);
//                        });
//                    })(bar, [cstate]);
                    done();
                });
            });
//            describe("activateTab() and focusTab()", function(){
//                it('should focus a tab', function(done) {
//                    tabs.activateTab();
//                    done();
//                });
//                it('should activate a tab on a focussed pane', function(done) {
//                    done();
//                });
//                it('should activate a tab but not focus it', function(done) {
//                    done();
//                });
//            });
//            describe("toggleButtons() and resizePanes()", function(){
//                it('should hide and show the pane buttons', function(done) {
//                    done();
//                });
//                it('should force resize the pane buttons', function(done) {
//                    done();
//                });
//            });
//            describe("All kinds of character sets and symbols", function(){
//                it('should display characters properly', function(done) {
//                    done();
//                });
//            });

            if (!onload.remain) {
                describe("unload()", function(){
                    it('should destroy all ui elements when it is unloaded', function(done) {
                        expect(tabs.getPanes()).length(5);
                        var els = tabs.getPanes();
                        tabs.unload();
                        
                        expect(tabs.getPanes()).length(0);
    
                        els.forEach(function(pane) {
                            expect(pane.aml.$amlDestroyed).to.equal(true);
                        });
                        done();
                    });
                });
                
                //@todo Idea: show in the tabs whether the editor is running atm
                // @todo test fs integration
                
                after(function(done) {
                    document.body.style.marginBottom = "";
                    done();
                });
            }
        });
        
        onload && onload();
    }
});