// Рекурсия: HTML tree
// Используя решение этого задания сделайте функцию, которая рекурсивно создает HTML - строку из древовидной структуры данных Javascript любой вложенности.Проверьте результат работы функции выводя HTML - строку используя document.write или же какой - то_элемент.innerHTML
{
    function htmlTree(data) {
        let copy
        copy = `<${data.tagName}`
        if (data.attrs) {
            for (const [attrName, attrParam] of Object.entries(data.attrs)) {
                copy += ` ${attrName}='${attrParam}'`
            }
        }
        copy += `>`
        if (data.children) {
            for (const child of data.children) {
                typeof child === 'object' ? copy += htmlTree(child) : copy += `${child}`
            }
        }
        copy += `</${data.tagName}>`
        return copy
    }

    // Проверка
    const table = {
        tagName: 'table',
        attrs: {
            border: "1",
        },
        children: [
            {
                tagName: 'tr',
                children: [
                    {
                        tagName: "td",
                        children: ["1x1"],
                    },
                    {
                        tagName: "td",
                        children: ["1x2"],
                    },
                ]
            },
            {
                tagName: 'tr',
                children: [
                    {
                        tagName: "td",
                        children: ["2x1"],
                    },
                    {
                        tagName: "td",
                        children: ["2x2"],
                    },
                ]
            }
        ]
    }
    htmlTree(table)
    document.write(htmlTree(table))
}


// Рекурсия: DOM tree
// Используя решение этого задания сделайте функцию, которая рекурсивно создает DOM из древовидной структуры данных Javascript.Задание в целом аналогично предыдущему, однако вместо накопления результата в HTML - строке функция должна добавлять элементы созданные через document.createElement в переданного в функцию родителя.
{
    function domTree(parent, data) {
        const tag = document.createElement(data.tagName)

        if (data.attrs) {
            for (const [attrName, attrParam] of Object.entries(data.attrs)) {
                tag[attrName] = attrParam
            }
        }

        parent.append(tag)

        if (data.children) {
            for (const child of data.children) {
                typeof child === 'object' ? domTree(tag, child) : tag.innerHTML = child
            }
        }
    }

    // Проверка
    const table = {
        tagName: 'table',
        attrs: {
            border: "1",
        },
        children: [
            {
                tagName: 'tr',
                children: [
                    {
                        tagName: "td",
                        children: ["1x1"],
                    },
                    {
                        tagName: "td",
                        children: ["1x2"],
                    },
                ]
            },
            {
                tagName: 'tr',
                children: [
                    {
                        tagName: "td",
                        children: ["2x1"],
                    },
                    {
                        tagName: "td",
                        children: ["2x2"],
                    },
                ]
            }
        ]
    }
    domTree(document.body, table)
}


// Рекурсия: Deep Copy
// Напишите функцию, которая рекурсивно осуществляет глубокое копирование структур Javascript, в которых нет циклических связей.
{
    function deepCopy(data) {
        let copy

        if (Array.isArray(data)) {
            copy = []
        } else if (typeof data === 'object' && data !== null) {
            copy = {}
        } else return data

        for (const item in data) {
            copy[item] = deepCopy(data[item])
        }

        return copy
    }


    // Проверка
    const arr = [1, "string", null, undefined, { a: 15, b: 10, c: [1, 2, 3, 4], d: undefined, e: true }, true, false]
    const arr2 = deepCopy(arr) //arr2 и все его вложенные массивы и объекты - другие объекты, которые можно менять без риска поменять что-то в arr

    const table = {
        tagName: 'table',
        attrs: {
            border: "1",
        },
        children: [
            {
                tagName: 'tr',
                children: [
                    {
                        tagName: "td",
                        children: ["1x1"],
                    },
                    {
                        tagName: "td",
                        children: ["1x2"],
                    },
                ]
            },
            {
                tagName: 'tr',
                children: [
                    {
                        tagName: "td",
                        children: ["2x1"],
                    },
                    {
                        tagName: "td",
                        children: ["2x2"],
                    },
                ]
            }
        ]
    }
    const table2 = deepCopy(table) //аналогично
}


// Рекурсия: My Stringify
// Напишите аналог JSON.stringify
{
    function stringify(data) {
        let copy = ''

        if (Array.isArray(data)) {
            copy += `[`
        } else if (typeof data === 'object' && data !== null) {
            copy += `{`
        } else return data

        for (const item in data) {

            if (data[item] == undefined) {
                copy += `${null}`
            } else if (typeof data[item] === 'number' || typeof data[item] === 'boolean') {
                copy += `${data[item]}`
            } else if (typeof data[item] === 'string') {
                copy += `"${data[item]}"`
            } else if (typeof data[item] === 'object' && data[item] !== null) {

                if (typeof data === 'object' && data !== null) {
                    copy += `{`
                    let i = 1
                    for (const [key, value] of Object.entries(data[item])) {

                        if (value == undefined) {
                            data[item][key] = null
                        } else if (typeof value !== 'object') {
                            copy += `"${key}":` + (typeof value === 'string' ? `"${value}"` : value)
                            if (i < Object.keys(data[item]).length) copy += ','
                        } else {
                            copy += `"${key}":${stringify(value)}`
                            copy += ','
                        }

                        i++
                    }
                }

                copy += `}`

            } else {
                copy += `${stringify(data[item])}`
            }

            if (item < (data.length - 1)) copy += ','
        }

        copy += `${Array.isArray(data) ? ']' : '}'} `

        return copy
    }


    const number = [1, 2, 3, false, "string", { a: 10, b: 'stepan' }]
    let test = stringify(number)
    console.log('sourse: ', JSON.stringify(number))
    console.log('sourse reverse: ', JSON.parse(JSON.stringify(number)))
    console.log('===============================================================================================')
    console.log('result: ', test)
    console.log('result reverse: ', JSON.parse(test))



    const arr = [1, "string", null, undefined, { a: 15, b: 10, c: [1, 2, 3, 4], d: undefined, e: true }, true, false]
    let jsonString = stringify(arr)
    console.log('sourse: ', JSON.stringify(arr))
    console.log('sourse reverse: ', JSON.parse(JSON.stringify(arr)))
    console.log('===============================================================================================')
    console.log('result: ', jsonString)
    console.log('result reverse: ', JSON.parse(jsonString))


    // пока не работает
    let tableParse = stringify(table)
    console.log('sourse: ', JSON.stringify(table))
    console.log('sourse reverse: ', JSON.parse(JSON.stringify(table)))
    console.log('===============================================================================================')
    console.log('result: ', tableParse)
    console.log('result reverse: ', JSON.parse(tableParse))

}


// Рекурсия: getElementById throw
// Напишите функцию getElementById, которая будет аналогична document.getElementById.В качестве основы можете взять материал лекции(walker), однако в цикл перебора children вставьте проверку на нахождение переданного id.При нахождении элемента по id в рекурсивной функции выбрасывайте исключение со значением найденного DOM - элемента, которое будет поймано на уровне вашей функции getElementById, после чего она вернет выброшенный DOM - элемент.
{
    function getElementById(idToFind) {
        function walker(parent = document.body) {
            for (const child of parent.children) {
                if (child.id == idToFind) {
                    throw child
                }
                walker(child)
            }
        }

        try {
            walker()
        }
        catch (e) {
            return console.log(e)
        }
    }

    // http://doc.a-level.com.ua/five-recursion-try-catch-finally-homework
    getElementById('h1-1_0')
}