
import {expect} from "chai"

import {
    addAttributeToken,
    addToObjectLink,
    clearAttributeTokens,
    containsAttributeToken,
    findClosestByAttribute,
    findClosestObjectLink,
    getLinkedObjects,
    hasObjectLink,
    removeAttributeToken,
    removeObjectLink,
    replaceAttributeToken,
    toggleAttributeToken,
    findClosestByClass
} from "../../../source/dom/attributes.mjs";

import {initJSDOM} from "../../util/jsdom.mjs";

let html1, html2, html3;

describe('Attributes', function () {
    before(function (done) {

        html1 = `<div id="test1"></div>`;
        html2 = `<div id="test1">
    <div id="sub1">
        <div id="sub2">
            <div id="sub3">
                <div id="sub4">
                    <div id="sub5"></div>
                </div>
            </div>
        </div>
    </div>
</div>
`;
        
        html3 = `<div data-monster-role="test1">
    <div data-monster-role="sub1" id="a1" class="sub1">
        <div data-monster-role="sub2" id="a2" class="sub2">
            <div data-monster-role="sub3" id="a3" class="sub3">
                <div data-monster-role="sub4" id="a4" class="sub4">
                    <div data-monster-role="sub5" id="a5" class="sub5"></div>
                </div>
            </div>
        </div>
    </div>
</div>
`;


        initJSDOM().then(() => {
            done()
        }).catch(e => done(e));
    });

    describe('ObjectLink', function () {

        const symbol = Symbol('mytest');

        beforeEach(() => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = html1;
        })

        afterEach(() => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = "";
        })

        it('should handle object-links', function () {
            let obj = {a: 1};
            let element = document.getElementById('test1');
            expect(hasObjectLink(element, symbol)).to.be.false;
            addToObjectLink(element, symbol, obj);
            expect(hasObjectLink(element, symbol)).to.be.true;

            let o = getLinkedObjects(element, symbol).next();
            expect(o.value).to.equal(obj);

            removeObjectLink(element, symbol);
            expect(hasObjectLink(element, symbol)).to.be.false;
            expect(() => getLinkedObjects(element, symbol)).to.throw(Error);
        })


    });

    describe('findClosestObjectLink()', function () {

        const symbol = Symbol('mytest');

        beforeEach(() => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = html2;
        })

        afterEach(() => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = "";
        })

        it('should return objectlink', function () {

            let sub4 = document.getElementById('sub4')
            let sub2 = document.getElementById('sub2')

            let obj = {};

            expect(hasObjectLink(sub2, symbol)).to.be.false;
            addToObjectLink(sub2, symbol, obj);
            expect(hasObjectLink(sub2, symbol)).to.be.true;

            let element = findClosestObjectLink(sub4);
            expect(element).is.instanceOf(HTMLDivElement);
            expect(element.getAttribute('id')).to.be.equal('sub2');

        });

    });

    describe('Attributes', function () {
        beforeEach(() => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = html3;
        })

        afterEach(() => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = "";
        })

        describe('find closest Attributes', function () {

            [
                ['a5', 'data-monster-role', undefined, 'sub5'],
                ['a5', 'data-monster-role', 'sub3', 'sub3'],
                ['a5', 'data-monster-role', 'sub1', 'sub1'],
                ['a4', 'data-monster-role', 'sub1', 'sub1'],
                ['a3', 'data-monster-role', 'sub1', 'sub1'],
                ['a2', 'data-monster-role', undefined, 'sub2'],
                ['a5', 'data-monster-role', 'sub5', 'sub5']
            ].forEach(function (data) {

                let a = data.shift()
                let b = data.shift()
                let c = data.shift()
                let d = data.shift()

                it('findClosestByAttribute(' + a + ', ' + b + ',' + c + ') should return ' + d, function () {
                    expect(findClosestByAttribute(document.getElementById(a), b, c).getAttribute('data-monster-role')).to.be.equal(d);
                })


            });
        }); 
        
        describe('find closest Element with class', function () {

            [
                ['a5',  'sub3', 'sub3'],
                ['a5',  'sub1', 'sub1'],
                ['a4',  'sub1', 'sub1'],
                ['a3',  'sub1', 'sub1'],
                ['a5',  'sub5', 'sub5']
            ].forEach(function (data) {

                let a = data.shift()
                let b = data.shift()
                let c = data.shift()
                it('findClosestByClass(' + a + ', ' + b + ') should return ' + c, function () {
                    expect(findClosestByClass(document.getElementById(a), b).getAttribute('class')).to.be.equal(c);
                })


            });
        });
    });

    describe('Attributes', function () {

        beforeEach(() => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = html1;
        })

        afterEach(() => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = "";
        })

        const atributeKey = 'data-test';

        it('toggleAttributeToken(element, key, value)', function () {
            let element = document.getElementById('test1');
            expect(element.hasAttribute(atributeKey)).to.be.false;
            element.setAttribute(atributeKey, 'apple bananna')
            toggleAttributeToken(element, atributeKey, 'pinapple');
            expect(element.getAttribute(atributeKey)).to.be.equal('apple bananna pinapple');
            toggleAttributeToken(element, atributeKey, 'pinapple');
            expect(element.getAttribute(atributeKey)).to.be.equal('apple bananna');
        })

        it('addAttributeToken(element, key, value)', function () {
            let element = document.getElementById('test1');
            expect(element.hasAttribute(atributeKey)).to.be.false;
            addAttributeToken(element, atributeKey, 'pinapple');
            expect(element.getAttribute(atributeKey)).to.be.equal('pinapple');
            addAttributeToken(element, atributeKey, 'bananna');
            expect(element.getAttribute(atributeKey)).to.be.equal('pinapple bananna');
        })

        it('removeAttributeToken(element, key, value)', function () {
            let element = document.getElementById('test1');
            element.setAttribute(atributeKey, 'apple bananna lemmon')
            removeAttributeToken(element, atributeKey, 'pinapple');
            expect(element.getAttribute(atributeKey)).to.be.equal('apple bananna lemmon');
            removeAttributeToken(element, atributeKey, 'bananna');
            expect(element.getAttribute(atributeKey)).to.be.equal('apple lemmon');

        })

        it('containsAttributeToken(element, key, value)', function () {
            let element = document.getElementById('test1');
            expect(containsAttributeToken(element, atributeKey, 'pinapple')).to.be.false;
            element.setAttribute(atributeKey, 'apple bananna')
            expect(containsAttributeToken(element, atributeKey, 'pinapple')).to.be.false;
            expect(containsAttributeToken(element, atributeKey, 'bananna')).to.be.true;
            expect(containsAttributeToken(element, atributeKey, 'apple')).to.be.true;

        })

        it(' replaceAttributeToken(element, key, value)', function () {
            let element = document.getElementById('test1');
            element.setAttribute(atributeKey, 'apple bananna tomato')
            replaceAttributeToken(element, atributeKey, 'tomato', 'lemmon');
            expect(element.getAttribute(atributeKey)).to.be.equal('apple bananna lemmon');
            replaceAttributeToken(element, atributeKey, 'bananna', 'pear');
            expect(element.getAttribute(atributeKey)).to.be.equal('apple pear lemmon');
        })

        it('clearAttributeTokens(element, key)', function () {
            let element = document.getElementById('test1');
            element.setAttribute(atributeKey, 'apple bananna')
            clearAttributeTokens(element, atributeKey);
            expect(element.getAttribute(atributeKey)).to.be.equal('');

        })


    })
})