/*jslint browser: true */
var chordDiagram = (function () {
    'use strict';

    var module = {},
        i,
        // 3 Header cell possibilities : empty, 'x', 'o'
        header_cell_empty = document.createElement('div'),
        header_cell_o = document.createElement('div'),
        header_cell_x = document.createElement('div');

    header_cell_o.appendChild(document.createElement('div'));
    header_cell_x.innerHTML = '×';

    function validateArray(array, size, max_value) {
        if ('object' !== typeof array) {
            return false;
        }

        for (i = 0; i < size; i += 1) {
            if ('number' !== typeof array[i] || array[i] % 1 !== 0 || array[i] < -1 || array[i] > max_value) {
                return false;
            }
        }
        return true;
    }



    function build_header(frets) {
        var header_row = document.createElement('div'),
            header_cell,
            num_strings = frets.length;
        header_row.className = 'header';

        for (i = 0; i < num_strings; i += 1) {

            if (frets[i] === 0) {
                header_cell = header_cell_o;
            } else if (frets[i] === -1) {
                header_cell = header_cell_x;
            } else {
                header_cell = header_cell_empty;
            }

            header_row.appendChild(header_cell.cloneNode(true));
        }
        return header_row;
    }

    function build_footer(frets, fingers) {
        var footer_row = document.createElement('div'),
            finger_cell,
            num_strings = fingers.length;
        footer_row.className = 'footer';

        for (i = 0; i < num_strings; i += 1) {
            finger_cell = document.createElement('div');

            if (frets[i] > 0) {
                if (fingers[i] === 0) {
                    finger_cell.innerHTML = 'T';
                } else if (fingers[i] > 0) {
                    finger_cell.innerHTML = fingers[i];
                }
            }

            footer_row.appendChild(finger_cell);
        }
        return footer_row;
    }


    module.build_diagram = function (frets, fingers) {

        var num_strings = frets.length,
            footer_row_needed = false,
            fret_min = 100,
            fret_max = 0,
            container,
            first_fret,
            fret,
            frets_row,
            fret_cell,
            fretno_cell,
            barre_start,
            barre_finish,
            barre_finger,
            barre_cell,
            knob_cell;

        if (!validateArray(frets, num_strings, 32)) {
            throw "Frets parameter format is invalid";
        }
        if (undefined !== fingers && !validateArray(fingers, num_strings, 4)) {
            throw "Fingers parameter format is invalid";
        }


        for (i = 0; i < num_strings; i += 1) {
            if (frets[i] > -1 && frets[i] > fret_max) {
                fret_max = frets[i];
            }
            if (frets[i] > 0 && frets[i] < fret_min) {
                fret_min = frets[i];
            }
            if ('object' === typeof fingers && fingers[i] !== -1) {
                footer_row_needed = true;
            }
        }

        container = document.createElement('div');
        container.className = 'chord-diagram';

        container.appendChild(build_header(frets));


        first_fret = fret_max > 5 ? fret_min : 1;

        for (fret = first_fret; fret < first_fret + 5; fret += 1) {
            frets_row = document.createElement('div');

            if (fret === 1) {
                frets_row.className = 'row first';
            } else if (fret === first_fret + 4) {
                frets_row.className = 'row last';
            } else {
                frets_row.className = 'row';
            }

            barre_start = -1;
            barre_finish = -1;
            barre_finger = -1;

            if (footer_row_needed) {
                for (i = 0; i < num_strings; i += 1) {
                    if (barre_start !== -1) {
                        if (frets[i] === fret && fingers[i] === barre_finger) {
                            barre_finish = i;
                        } else if (frets[i] < fret || (frets[i] === fret && fingers[i] !== barre_finger)) {
                            if (barre_finish !== -1) {
                                break; // exiting
                            }
                            barre_start = -1; // resetting
                        }
                    }

                    if (barre_start === -1 && fingers[i] !== -1 && frets[i] === fret) {
                        barre_start = i;
                        barre_finger = fingers[i];
                    }
                }

                if (barre_finish <= barre_start) {
                    barre_start = -1;
                }
            }

            for (i = 0; i < num_strings - 1; i += 1) {
                fret_cell = document.createElement('div');

                if (i === barre_start) {
                    barre_cell = document.createElement('div');
                    barre_cell.className = 'barre barre-' + (barre_finish - barre_start);

                    fret_cell.appendChild(barre_cell);
                } else if (i < barre_start || i >= barre_finish) {
                    if (i !== barre_finish && frets[i] === fret) {
                        knob_cell = document.createElement('div');
                        knob_cell.className = 'knob';

                        fret_cell.appendChild(knob_cell);
                    }

                    if (i === num_strings - 2 && frets[num_strings - 1] === fret) {
                        knob_cell = document.createElement('div');
                        knob_cell.className = 'knob right';

                        fret_cell.appendChild(knob_cell);
                    }
                }

                frets_row.appendChild(fret_cell);
            }

            if (fret === first_fret && fret !== 1) {
                fretno_cell = document.createElement('div');
                fretno_cell.className = 'fretno';
                fretno_cell.innerHTML = fret;

                frets_row.appendChild(fretno_cell);
            }

            container.appendChild(frets_row);
        }

        if (footer_row_needed) {
            container.appendChild(build_footer(frets, fingers));
        }

        return container;

    };

    module.on_load = function () {
        return module.replace_tags();
    };

    module.replace_tags = function (container, classname, tagname) {

        // default arguments
        if (container === undefined) {
            container = document.body;
        }
        if (classname === undefined) {
            classname = 'chord-diagram';
        }
        if (tagname === undefined) {
            tagname = 'div';
        }

        var diagram_tags = container.getElementsByClassName(classname),
            j,
            diagram_number,
            diagram_tag,
            shift,
            frets,
            frets_string,
            frets_number,
            fret_char,
            fingers,
            fingers_string,
            finger_char,
            diagram;

        diagram_number = diagram_tags.length;
        for (j = 0; j < diagram_number; j += 1) {

            diagram_tag = diagram_tags[j];
            if (typeof diagram_tag === 'object') {

                frets_string = diagram_tag.getAttribute('data-frets');
                if (frets_string) {

                    shift = +diagram_tag.getAttribute('data-shift');
                    frets_number = frets_string.length;
                    frets = [];

                    for (i = 0; i < frets_number; i += 1) {
                        fret_char = frets_string.charAt(i).toLowerCase();
                        if (fret_char === 'x') {
                            frets[i] = -1;
                        } else {
                            frets[i] = +fret_char + shift;
                        }
                    }

                    fingers_string = diagram_tag.getAttribute('data-fingers');
                    if (fingers_string && frets_number <= fingers_string.length) {
                        fingers = [];
                        for (i = 0; i < frets_number; i += 1) {
                            finger_char = fingers_string.charAt(i).toLowerCase();
                            if (finger_char === 'x') {
                                fingers[i] = -1;
                            } else {
                                fingers[i] = +finger_char;
                            }
                        }
                        diagram = module.build_diagram(frets, fingers);
                    } else {
                        diagram = module.build_diagram(frets);
                    }

                    diagram_tag.innerHTML = diagram.innerHTML;
                }
            }
        }
    };

    return module;
}());


/*
//Code example to load it automatically:
if (window.jQuery) {
    window.jQuery.ready(chordDiagram.on_load);
} else {
    var oldonload = window.onload;
    if (typeof window.onload !== 'function') {
        window.onload = chordDiagram.on_load;
    } else {
        window.onload = function () {
            if (oldonload) {
                oldonload();
            }
            chordDiagram.on_load();
        };
    }
}
// */