/* global AJS:false */
AJS.test.require("com.atlassian.bitbucket.server.bitbucket-web:filetable", function() {

    var pageState;
    var Path;
    var FileTableResource;

    module('file-table', {
        setup : function() {
            pageState = require('bitbucket/internal/model/page-state');
            Path = require('bitbucket/internal/model/path');
            FileTableResource = require('bitbucket/internal/feature/filebrowser/file-table');

            this.pageStateValues = {
                repoSlug: 'repo-slug',
                repoName: 'repo-name',
                projectKey: 'PROJ-KEY'
            };

            var self = this;

            sinon.stub(pageState, "getProject", function () {
                return {
                    getKey: function() { return self.pageStateValues.projectKey; }
                };
            });
            sinon.stub(pageState, "getRepository", function () {
                return {
                    getSlug : function() { return self.pageStateValues.repoSlug; },
                    getName : function() { return self.pageStateValues.repoName; }
                };
            });
        },
        teardown: function () {
            pageState.getProject.restore();
            pageState.getRepository.restore();

            pageState = undefined;
            Path = undefined;
            FileTableResource = undefined;
        }
    });

    function createFile (name) {
        return createNode('FILE', name);
    }

    function createDir (name) {
        return createNode('DIRECTORY', name);
    }

    function createSubmodule(name) {
        return createNode('SUBMODULE', name);
    }

    function createNode(type, name) {
        return {
            path: new Path('blah/' + name),
            type: type
        };
    }

    function assertFile(result, fileName) {
        equal(result.path.getName(), fileName, "Result did not have expected name " + fileName);
        equal(result.type, "FILE", "Result was not of type 'FILE'");
    }

    function assertDir(result, fileName) {
        equal(result.path.getName(), fileName, "Result did not have expected name " + fileName);
        equal(result.type, "DIRECTORY", "Result was not of type 'DIRECTORY'");
    }

    function assertSubmodule(result, fileName) {
        equal(result.path.getName(), fileName, "Result did not have expected name " + fileName);
        equal(result.type, "SUBMODULE", "Result was not of type 'SUBMODULE'");
    }

    test('File table sorts empty files', function() {
        var files = [];
        var fileTableView = new FileTableResource.FileTableView();
        var sorted = fileTableView.getSortedFiles(files);
        ok(sorted, "Sorted files should exist");
        equal(sorted.length, 0, "Sorted file size should be empty");
    });

    test('File table sorts only files alphabetically', function() {
        var files = [
            createFile("a"),
            createFile("A"),
            createFile("b"),
            createFile("C"),
            createFile("d"),
            createFile("e")
        ];
        var fileTableView = new FileTableResource.FileTableView();
        var sorted = fileTableView.getSortedFiles(files);
        ok(sorted, "Sorted files should exist");
        equal(sorted.length, 6, "Sorted file size should be the same");
        assertFile(sorted[0], "A");
        assertFile(sorted[1], "a");
        assertFile(sorted[2], "b");
        assertFile(sorted[3], "C");
        assertFile(sorted[4], "d");
        assertFile(sorted[5], "e");
    });

    test('File table sorts only directories alphabetically', function() {
        var files = [
            createDir("a"),
            createDir("A"),
            createDir("b"),
            createDir("C"),
            createDir("d"),
            createDir("e")
        ];
        var fileTableView = new FileTableResource.FileTableView();
        var sorted = fileTableView.getSortedFiles(files);
        ok(sorted, "Sorted files should exist");
        equal(sorted.length, 6, "Sorted file size should be the same");
        assertDir(sorted[0], "A");
        assertDir(sorted[1], "a");
        assertDir(sorted[2], "b");
        assertDir(sorted[3], "C");
        assertDir(sorted[4], "d");
        assertDir(sorted[5], "e");
    });

    test('File table sorts directories before files/submodules', function() {
        var files = [
            createDir("a"),
            createFile("e"),
            createDir("A"),
            createDir("b"),
            createFile("b"),
            createSubmodule("a"),
            createFile("A"),
            createSubmodule("C"),
            createFile("d"),
            createDir("C"),
            createDir("d"),
            createDir("e")
        ];
        var fileTableView = new FileTableResource.FileTableView();
        var sorted = fileTableView.getSortedFiles(files);
        ok(sorted, "Sorted files should exist");
        equal(sorted.length, 12, "Sorted file size should be the same");
        assertDir(sorted[0], "A");
        assertDir(sorted[1], "a");
        assertDir(sorted[2], "b");
        assertDir(sorted[3], "C");
        assertDir(sorted[4], "d");
        assertDir(sorted[5], "e");
        assertFile(sorted[6], "A");
        assertSubmodule(sorted[7], "a");
        assertFile(sorted[8], "b");
        assertSubmodule(sorted[9], "C");
        assertFile(sorted[10], "d");
        assertFile(sorted[11], "e");
    });

    function assertPathParseResult(result, project, repo, path, query) {
        equal(result.projectKey, project, "Project key parsed correctly");
        equal(result.repoSlug, repo, "Repo slug parsed correctly");
        equal(result.path, path, "Path parsed correctly");
        if (query !== undefined) {
            equal(result.query, query, "Query parsed correctly");
        } else {
            ok(result.query === undefined, "Query is undefined");
        }
    }

    test('Path url parsing', function () {
        var fileTable = new FileTableResource.FileTable("path", {
            toJSON: function () {
                return {};
            }
        });

        this.pageStateValues.repoSlug = 'qa-resources';
        this.pageStateValues.projectKey = 'QA';

        assertPathParseResult(fileTable.parsePathUrl("http://sonoma:7990/bitbucket/projects/QA/repos/qa-resources/browse/this/dir"), "QA", "qa-resources", "this/dir");
        assertPathParseResult(fileTable.parsePathUrl("http://sonoma:7990/bitbucket/projects/QA/repos/qa-resources/browse/this/dir/"), "QA", "qa-resources", "this/dir/");

        sinon.stub(AJS, "contextPath", function () {
            return "";
        });

        assertPathParseResult(fileTable.parsePathUrl("http://sonoma/projects/QA/repos/qa-resources/browse/this/dir?at=branch"), "QA", "qa-resources", "this/dir", "?at=branch");
        assertPathParseResult(fileTable.parsePathUrl("http://sonoma/projects/QA/repos/qa-resources/browse/this/dir?at=branch&limit=10"), "QA", "qa-resources", "this/dir", "?at=branch&limit=10");
        assertPathParseResult(fileTable.parsePathUrl("http://sonoma/projects/QA/repos/qa-resources/browse/this/dir?at=branch&limit=10#foo"), "QA", "qa-resources", "this/dir", "?at=branch&limit=10");
        assertPathParseResult(fileTable.parsePathUrl("http://sonoma/projects/QA/repos/qa-resources/browse/this/dir#anchor"), "QA", "qa-resources", "this/dir");
        assertPathParseResult(fileTable.parsePathUrl("http://sonoma/projects/QA/repos/qa-resources/browse/projects/QA/repos/qa-resources#anchor"), "QA", "qa-resources", "projects/QA/repos/qa-resources");
        assertPathParseResult(fileTable.parsePathUrl("http://sonoma/projects/QA/repos/qa-resources/browse/projects/QA/repos/qa-resources?limit=10#foo"), "QA", "qa-resources", "projects/QA/repos/qa-resources", "?limit=10");
        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/QA/repos/qa-resources/browse/this/dir"), "QA", "qa-resources", "this/dir");
        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/QA/repos/qa-resources/browse/ba%20r/baz.xml"), "QA", "qa-resources", "ba r/baz.xml");
        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/QA/repos/qa-resources/browse"), "QA", "qa-resources", "");
        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/QA/repos/qa-resources/browse?limit=10"), "QA", "qa-resources", "", "?limit=10");
        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/QA/repos/qa-resources/browse#foo"), "QA", "qa-resources", "");

        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/QA/repos/qa-resources/browse/#foo"), "QA", "qa-resources", "");

        this.pageStateValues.repoSlug = 'ba r';
        this.pageStateValues.projectKey = 'ba r';

        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/ba%20r/repos/ba%20r/browse/"), "ba r", "ba r", "");
        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/ba%20r/repos/ba%20r/browse/ba%20r"), "ba r", "ba r", "ba r");
        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/ba%20r/repos/ba%20r/browse/projects/ba%20r/repos/ba%20r/browse"), "ba r", "ba r", "projects/ba r/repos/ba r/browse");
        assertPathParseResult(fileTable.parsePathUrl("sonoma/projects/ba%20r/repos/ba%20r/browse/projects/ba%20r/repos/ba%20r/browse?limit=1"), "ba r", "ba r", "projects/ba r/repos/ba r/browse", "?limit=1");

        AJS.contextPath.restore();
    });

    test('Get child path difference between URLS', function() {
        /*jshint maxlen:450*/
        var getChildPathDifferenceBetweenUrls = FileTableResource.getChildPathDifferenceBetweenUrls;

        this.pageStateValues.repoSlug = 'test-resources';
        this.pageStateValues.projectKey = 'TEST';

        equal(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0/dir1', 'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0'), 'dir1', 'Prev url is directory');
        equal(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0/dir1/file1.txt', 'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0/dir1'), 'file1.txt', 'Prev url is file');
        equal(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/diff/dir0/dir1/file1.txt', 'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0/dir1'), 'file1.txt', 'Prev url is file from diff view');
        equal(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/diff/dir0/dir1/file1.txt?until=3418c7fb02cd594b0c0ecfccb0dffb4fb93707ce', 'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0/dir1'),
            'file1.txt', 'Prev url is file from diff view and has querystring params');
        equal(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/diff/dir0/dir1/file1.txt?at=33173b0f34a6fed1aa6f8a9245de6280b6ac5591&until=33173b0f34a6fed1aa6f8a9245de6280b6ac5591',
                'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0/dir1?at=33173b0f34a6fed1aa6f8a9245de6280b6ac5591'), 'file1.txt', 'Prev url is file from diff view and both urls have querystring params');
        equal(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0/dir1/file1.txt', 'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse'), 'dir0', 'Prev url is multiple levels deeper than current url');
        equal(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0/dir1/', 'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0'), 'dir1', 'Prev url ends in /');
        strictEqual(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0', 'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0'), null, 'Prev url is the same as the current url');
        strictEqual(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/anotherDir/dir2', 'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0'), null, 'Prev url is not a child of current url');
        strictEqual(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0', 'http://localhost:7990/bitbucket/projects/TEST/repos/test-resources/browse/dir0/dir1'), null, 'Prev url is parent of current url');
        strictEqual(getChildPathDifferenceBetweenUrls(null, null), null, 'Urls are null');
        strictEqual(getChildPathDifferenceBetweenUrls(undefined, undefined), null, 'Urls are undefined');
        strictEqual(getChildPathDifferenceBetweenUrls([], {}), null, 'Urls are not strings');
        strictEqual(getChildPathDifferenceBetweenUrls('http:localhost:7990stashprojects/TESTrepostest-resourcesbrowsedir0', 'http:localhost:7990stashprojects/TESTrepostest-resourcesbrowse'), null, 'Urls are not valid paths');
        strictEqual(getChildPathDifferenceBetweenUrls('http://localhost:7990/bitbucket/projects/STASH/repos/stash/browse/dir0/dir1', 'http://localhost:7990/bitbucket/projects/STASH/repos/stash/browse/dir0'), null, 'Urls are not from current project & repo');
    });

});