'use strict';

oml.ui.infoView = function(externalData, isMixed) {

    isMixed = isMixed || {};

    var ui = oml.user.ui,

        arrayKeys = ['author', 'place', 'publisher', 'language', 'categories'],

        iconSize = externalData ? 256 : ui.iconSize,

        isMultiple = arguments.length == 2,

        separator = '; ',

        css = getCSS(iconSize, oml.config.iconRatio),

        that = Ox.Element()
            .addClass('OxTextPage')
            .css({overflowY: 'auto'})
            .bindEvent({
                oml_icons: function() {
                    that.updateElement(ui.item, [$icon])
                },
                oml_item: function() {
                    if (ui.item) {
                        that.updateElement(ui.item);
                    }
                },
                oml_listselection: function(data) {
                    if (
                        data.value
                        && data.value.length
                        && data.value[0] != ui.item
                    ) {
                        that.updateElement(data.value[0]);
                    }
                }
            }),

        $icon = Ox.Element()
            .css({
                position: 'absolute',
                left: '16px',
                top: '16px',
                width: css.icon.width
            })
            .appendTo(that),

        $info = Ox.Element()
            .addClass('OxSelectable')
            .css({
                position: 'absolute',
                left: !isMultiple ? css.info.left : '16px',
                right: !externalData && !isMultiple
                    ? '176px' : 16 + Ox.UI.SCROLLBAR_SIZE + 'px',
                top: '16px'
            })
            [iconSize == 512 ? 'hide' : 'show']()
            .appendTo(that),

        $data,

        $image, $reflection, $reflectionImage;

    if (!externalData) {
        $data = Ox.Element()
            .addClass('OxSelectable')
            .css({
                position: 'absolute',
                right: '16px',
                top: '16px',
                width: '128px'
            })
            .appendTo(that);
    }

    function formatLight(string) {
        return '<span class="OxLight">' + string + '</span>';
    }

    function formatKey(key) {
        return '<span style="font-weight: bold">'
            + Ox._(Ox.getObjectById(oml.config.itemKeys, key).title)
            + ':</span>&nbsp;';
    }

    function formatValue(value, key) {
        var isEditor = key == 'author' && (value || []).some(function(value) {
            return Ox.endsWith(value, ' (Ed.)');
        });
        return value ? (Ox.isArray(value) ? value : [value]).map(function(value) {
            if (key == 'date' && value) {
                value = value.slice(0, 4);
            }
            return (
                key && !externalData ? '<a href="/' + key + '==' + value + '">' : ''
            ) + (
                key == 'author' ? value.replace(/ \(Ed\.\)$/, '') : value
            ) + (
                key && !externalData ? '</a>' : ''
            );
        }).join(separator) + (isEditor ? ' (Ed.)' : '') : '';
    }

    function getCSS(size, ratio) {
        var width = Math.round(ratio >= 1 ? size : size * ratio),
            height = Math.round(ratio <= 1 ? size : size / ratio),
            left = size == 256 ? Math.floor((size - width) / 2) : 0;
        return {
            icon: {
                width: size + 'px'
            },
            info: {
                left: (size == 256 ? size + 32 : width + 48) + 'px'
            },
            image: {
                left: left + 'px',
                width: width + 'px',
                height: height + 'px'
            },
            reflection: {
                top: height + 'px'
            }
        };
    }

    function renderIdentifyButton(data) {
        return Ox.Button({
                disabled: data.mediastate != 'available',
                style: 'squared',
                title: Ox._('Identify Book...'),
                width: 128
            })
            .css({marginTop: '8px'})
            .bindEvent({
                click: function() {
                    oml.$ui.identifyDialog = oml.ui.identifyDialog(data).open();
                }
            });
    }

    function renderMediaButton(data) {

        function getListItems() {
            var items = [];
            if (ui._lists) {
                items = ui._lists.filter(function(list) {
                    return list.user === ''
                        && list.type != 'smart';
                }).map(function(list) {
                    return {
                        id: list.id,
                        title: Ox._('Download to {0}', [
                            Ox.encodeHTMLEntities(list.name)
                        ])
                    };
                });
                items.splice(1, 0, [{}]);
            }
            return items;
        }

        function setListItems() {
            if ($element && ui._lists) {
                $element.options({
                    disabled: false
                }).options('elements')[1].options({
                    items: getListItems()
                });
            } else {
                setTimeout(setListItems, 100);
            }
        }
        
        if (data.mediastate == 'unavailable' && !ui._lists) {
            setListItems();
        }

        var $element = (data.mediastate == 'unavailable' || Ox.isUndefined(data.mediastate))
            ? Ox.FormElementGroup({
                elements: [
                    Ox.Button({
                        style: 'squared',
                        title: Ox._('Download Book'),
                        width: 112
                    })
                    .bindEvent({
                        click: function() {
                            var _this = this;
                            this.options({disabled: true});
                            oml.api.download({id: ui.item}, function(result) {
                                _this.options({disabled: false});
                                data.mediastate = 'transferring';
                                that.updateElement(data, $data);
                            });
                        }
                    }),
                    Ox.MenuButton({
                        disabled: !ui._lists,
                        items: getListItems(),
                        overlap: 'left',
                        style: 'squared',
                        title: 'select',
                        tooltip: Ox._('Download Book to a List'),
                        type: 'image'
                    })
                    .bindEvent({
                        click: function(data_) {
                            data.mediastate = 'transferring';
                            that.updateElement(data, $data);
                            oml.api.addListItems({
                                items: [ui.item],
                                list: data_.id
                            }, function(result) {
                                // ...
                            });
                        }
                    })
                ],
                float: 'right'
            })
            : data.mediastate == 'transferring'
            ? Ox.FormElementGroup({
                elements: [
                    Ox.Button({
                        style: 'squared',
                        title: Ox._('Transferring...'),
                        width: 112
                    })
                    .bindEvent({
                        click: function() {
                            oml.UI.set({page: 'transfers'});
                        }
                    }),
                    Ox.Button({
                        overlap: 'left',
                        style: 'squared',
                        title: 'close',
                        tooltip: Ox._('Cancel Transfer'),
                        type: 'image'
                    })
                    .bindEvent({
                        click: function() {
                            data.mediastate = 'unavailable';
                            that.updateElement(data, $data);
                            oml.api.cancelDownloads({ids: [ui.item]}, function() {
                                that.updateElement(ui.item, $data);
                            });
                        }
                    })
                ],
                float: 'right'
            })
            : Ox.FormElementGroup({
                elements: [
                    Ox.Button({
                        style: 'squared',
                        title: Ox._('Read Book'),
                        width: 112
                    })
                    .bindEvent({
                        click: function() {
                            oml.UI.set({itemView: 'book'});
                        }
                    }),
                    Ox.MenuButton({
                        items: [
                            {id: 'read', title: Ox._('Read in Open Media Libary')},
                            {id: 'open', title: Ox._('Open in External Reader')},
                            {},
                            {id: 'show', title: Ox._('Show File')}
                        ],
                        overlap: 'left',
                        style: 'squared',
                        title: 'select',
                        tooltip: Ox._('Download Book to a List'),
                        type: 'image'
                    })
                    .bindEvent({
                        click: function(data_) {
                            if (data_.id == 'read') {
                                oml.UI.set({itemView: 'book'});
                            } else if (data_.id == 'open') {
                                // ...
                            } else {
                                oml.api.openFolder({id: oml.user.ui.item});
                            }
                        }
                    })
                ],
                float: 'right'
            });
        return $element;
    }

    function renderShareButton() {
        return Ox.Checkbox({
                style: 'squared',
                title: Ox._('Share Metadata'),
                value: false,
                width: 128,
            })
            .css({marginTop: '8px'})
            .bindEvent({
                change: function(data) {
                    // ...
                }
            });
    }

    function splitValue(value, key) {
        var isEditor = key == 'author'
            && Ox.decodeHTMLEntities(value).split(separator).some(function(value) {
                return Ox.endsWith(value, ' (Ed.)');
            });
        return value ? Ox.unique(
            Ox.decodeHTMLEntities(value).split(separator).map(function(value) {
                value = Ox.encodeHTMLEntities(value);
                return isEditor
                    ? value.replace(/ \(Ed\.\)$/, '') + ' (Ed.)'
                    : value;
            })
        ) : [];
    }

    function toggleCoverSize(ratio) {
        var css;
        iconSize = iconSize == 256 ? 512 : 256,
        css = getCSS(iconSize, ratio);
        //$icon.animate(css.icon, 250);
        $info.animate(css.info, 250);
        $image.animate(css.image, 250);
        $reflectionImage.animate(css.image, 250);
        $reflection.animate(css.reflection, 250);
        oml.UI.set({iconSize: iconSize});
    }

    function updateCover(ratio) {
        var css = getCSS(iconSize, ratio);
        $image.css(css.image).show();
        $reflectionImage.css(css.image);
        $reflection.css(css.reflection).show();
    }

    that.updateCover = function(url) {
        Ox.Request.clearCache('get');
        that.updateElement(ui.item, $icon);
    };

    that.updateElement = function(idOrData, $elements) {

        var data = Ox.isObject(idOrData) ? idOrData : null,
            id = data ? null : idOrData,

        $elements = $elements 
            ? Ox.makeArray($elements)
            : [$icon, $info, $data];

        (data ? Ox.noop : oml.api.get)({
            id: id,
            keys: []
        }, function(result) {

            if (!externalData && id && id != ui.item) {
                return;
            }

            if (result) {
                data = result.data;
            }

            Ox.print('BOOK DATA', data)

            var $div,
                isEditable = isMultiple || (
                    data.mediastate == 'available' && !externalData
                ),
                src = !externalData
                    ? '/' + data.id + '/' + ui.icons + '512.jpg?' + data.modified
                    : data.cover,
                ratio = (
                    ui.icons == 'cover' || externalData
                    ? data.coverRatio : data.previewRatio
                ) || oml.config.iconRatio,
                size = iconSize,
                reflectionSize = Math.round(size / 2);

            $elements.forEach(function($element) {

                $element.empty();

                if ($element == $icon) {

                    $image = Ox.Element({
                            element: '<img>',
                            tooltip: !externalData
                                ? Ox._('Doubleclick to edit')
                                : ''
                        })
                        .on({
                            error: function() {
                                if (size == 512) {
                                    $info.show();
                                }
                            },
                            load: function() {
                                ratio = $image[0].width / $image[0].height;
                                updateCover(ratio);
                                if (size == 512) {
                                    $info.css({
                                        left: getCSS(512, ratio).info.left
                                    }).show();
                                }
                            }
                        })
                        .attr({src: src})
                        .css({
                            position: 'absolute'
                        })
                        .hide()
                        .bindEvent({
                            doubleclick: function() {
                                if (!externalData) {
                                    oml.$ui.coverDialog = oml.ui.coverDialog(
                                        id, data.cover
                                    ).open();
                                }
                            },
                            singleclick: function() {
                                if (!externalData) {
                                    toggleCoverSize(ratio);
                                }
                            }
                        })
                        .appendTo($icon);

                    $reflection = $('<div>')
                        .addClass('OxReflection')
                        .css({
                            position: 'absolute',
                            width: size + 'px',
                            height: reflectionSize + 'px',
                            overflow: 'hidden'
                        })
                        .hide()
                        .appendTo($icon);

                    $reflectionImage = $('<img>')
                        .attr({src: src})
                        .css({
                            position: 'absolute'
                        })
                        .appendTo($reflection);

                    $('<div>')
                        .css({
                            position: 'absolute',
                            width: size + 'px',
                            height: reflectionSize + 'px'
                        })
                        .appendTo($reflection);

                } else if ($element == $info) {

                    // -------- Title --------

                    $('<div>')
                        .css({
                            marginTop: '-2px'
                        })
                        .append(
                            Ox.EditableContent({
                                    clickLink: oml.clickLink,
                                    editable: isEditable,
                                    placeholder: formatLight(Ox._(
                                        isMixed.title ? 'Mixed Title' : 'Unknown Title'
                                    )),
                                    tooltip: isEditable ? oml.getEditTooltip() : '',
                                    value: Ox.encodeHTMLEntities(data.title || '')
                                })
                                .css({
                                    fontWeight: 'bold',
                                    fontSize: '13px'
                                })
                                .bindEvent({
                                    submit: function(event) {
                                        editMetadata('title', Ox.decodeHTMLEntities(event.value));
                                    }
                                })
                        )
                        .appendTo($info);

                    // -------- Author --------

                    $('<div>')
                        .css({
                            marginTop: '2px'
                        })
                        .append(
                            Ox.EditableContent({
                                    clickLink: oml.clickLink,
                                    editable: isEditable,
                                    format: function(value) {
                                        return formatValue(splitValue(value, 'author'), 'author');
                                    },
                                    placeholder: formatLight(Ox._(
                                        isMixed.author ? 'Mixed Author' : 'Unknown Author'
                                    )),
                                    tooltip: isEditable ? oml.getEditTooltip() : '',
                                    value: Ox.encodeHTMLEntities(
                                        (data.author || []).map(function(value, index) {
                                            return index < data.author.length - 1
                                                ? value.replace(/ \(Ed\.\)$/, '')
                                                : value;
                                        }).join(separator)
                                    )
                                })
                                .css({
                                    marginBottom: '-3px',
                                    fontWeight: 'bold',
                                    fontSize: '13px'
                                })
                                .bindEvent({
                                    submit: function(event) {
                                        editMetadata('author', Ox.decodeHTMLEntities(event.value));
                                    }
                                })
                        )
                        .appendTo($info);

                    // -------- Publisher, Place, Date --------

                    $div = $('<div>')
                        .css({
                            marginTop: '4px',
                        })
                        .appendTo($info);
                    ['publisher', 'place', 'date'].forEach(function(key, index) {
                        if (index) {
                            $('<span>').html(', ').appendTo($div);
                        }
                        $('<span>')
                            .html(formatKey(key))
                            .appendTo($div);
                        Ox.EditableContent({
                                clickLink: oml.clickLink,
                                editable: isEditable,
                                format: function(value) {
                                    return formatValue(
                                        Ox.contains(arrayKeys, key)
                                        ? splitValue(value) : value,
                                        key
                                    );
                                },
                                placeholder: formatLight(Ox._(
                                    isMixed[key] ? 'mixed' : 'unknown'
                                )),
                                tooltip: isEditable ? oml.getEditTooltip() : '',
                                value: Ox.encodeHTMLEntities(
                                    Ox.contains(arrayKeys, key)
                                    ? (data[key] || []).join(separator)
                                    : (data[key] || '')
                                )
                            })
                            .bindEvent({
                                submit: function(event) {
                                    editMetadata(key, Ox.decodeHTMLEntities(event.value));
                                }
                            })
                            .appendTo($div);
                    });

                    // -------- Series, Edition, Language, Pages --------

                    $div = $('<div>')
                        .css({
                            marginTop: '4px',
                        })
                        .appendTo($info);
                    ['series', 'edition', 'language', 'pages'].forEach(function(key, index) {
                        if (index) {
                            $('<span>').html(', ').appendTo($div);
                        }
                        $('<span>')
                            .html(formatKey(key))
                            .appendTo($div);
                        Ox.EditableContent({
                                clickLink: oml.clickLink,
                                editable: isEditable,
                                format: function(value) {
                                    return (
                                        Ox.contains(['series', 'language'], key)
                                        ? formatValue : Ox.identity
                                    )(
                                        Ox.contains(arrayKeys, key)
                                        ? splitValue(value) : value,
                                        key
                                    );
                                },
                                placeholder: formatLight(Ox._(
                                    isMixed[key] ? 'mixed' : 'unknown'
                                )),
                                tooltip: isEditable ? oml.getEditTooltip() : '',
                                value: Ox.encodeHTMLEntities(
                                    Ox.contains(arrayKeys, key)
                                    ? (data[key] || []).join(separator)
                                    : (data[key] || '')
                                )
                            })
                            .bindEvent({
                                submit: function(event) {
                                    editMetadata(key, Ox.decodeHTMLEntities(event.value));
                                }
                            })
                            .appendTo($div);
                    });

                    // -------- Categories --------

                    if (data.categories || isEditable) {
                        $div = $('<div>')
                            .css({
                                marginTop: '4px',
                            })
                            .appendTo($info);
                        $('<span>')
                            .html(formatKey('categories'))
                            .appendTo($div);
                        Ox.EditableContent({
                                clickLink: oml.clickLink,
                                editable: isEditable,
                                format: function(value) {
                                    return formatValue(splitValue(value), 'categories');
                                },
                                placeholder: formatLight(Ox._(
                                    isMixed.categories ? 'mixed' : 'unknown'
                                )),
                                tooltip: isEditable ? oml.getEditTooltip() : '',
                                value: Ox.encodeHTMLEntities((data.categories || []).join(separator))
                            })
                            .bindEvent({
                                submit: function(event) {
                                    editMetadata('categories', Ox.decodeHTMLEntities(event.value));
                                }
                            })
                            .appendTo($div);
                    }

                    // -------- ISBN --------

                    if (data.isbn || isEditable) {
                        $div = $('<div>')
                            .css({
                                marginTop: '4px',
                            })
                            .appendTo($info);
                        $('<span>')
                            .html(formatKey('isbn'))
                            .appendTo($div);
                        Ox.EditableContent({
                                editable: isEditable,
                                format: function(value) {
                                    return (value ? [
                                        Ox.formatISBN(value, 13, true),
                                        Ox.formatISBN(value, 10, true)
                                    ] : []).join(separator);
                                },
                                placeholder: formatLight(Ox._(
                                    isMixed.isbn ? 'mixed' : 'unknown'
                                )),
                                tooltip: isEditable ? oml.getEditTooltip() : '',
                                value: Ox.formatISBN(data.isbn || '', 13, true)
                            })
                            .bindEvent({
                                submit: function(event) {
                                    this.options({
                                        value: Ox.formatISBN(event.value, 13, true)
                                    });
                                    editMetadata(
                                        'isbn', Ox.formatISBN(event.value, 13)
                                    );
                                }
                            })
                            .appendTo($div);
                    }

                    // -------- Description, Table of Contents --------

                    ['description', 'tableofcontents'].forEach(function(key) {
                        if (data[key] || isEditable) {
                            $('<div>')
                                .css({
                                    marginTop: '8px',
                                    textAlign: 'justify'
                                })
                                .append(
                                    Ox.EditableContent({
                                            clickLink: oml.clickLink,
                                            editable: isEditable,
                                            format: function(value) {
                                                return value.replace(/\n/g, '<br>');
                                            },
                                            placeholder: formatLight(Ox._(
                                                isMixed[key] ? 'Mixed {0}' : 'No {0}', [
                                                Ox.getObjectById(oml.config.itemKeys, key).title
                                            ])),
                                            tooltip: isEditable ? oml.getEditTooltip() : '',
                                            type: 'textarea',
                                            value: Ox.encodeHTMLEntities(data[key] || '')
                                        })
                                        .bindEvent({
                                            submit: function(event) {
                                                editMetadata(
                                                    key,
                                                    Ox.decodeHTMLEntities(event.value).replace(/<br>/g, '\n')
                                                );
                                            }
                                        })
                                )
                                .appendTo($info);
                        }
                    });

                    $('<div>').css({height: '16px'}).appendTo($info);

                    oml.createLinks($info);

                } else if ($element == $data) {

                    renderMediaButton(data).appendTo($data);

                    $('<div>')
                        .addClass('OxSelectable')
                        .css({
                            marginTop: '10px',
                        })
                        .text(
                            [
                                data.extension.toUpperCase(),
                                Ox.formatValue(data.size, 'B')
                            ].join(', ')
                        )
                        .appendTo($data);

                    renderIdentifyButton(data).appendTo($data);

                    ['accessed', 'modified', 'added', 'created'].forEach(function(id) {
                        var title;
                        if (data[id]) {
                            title = Ox.getObjectById(oml.config.itemKeys, id).title;
                            $('<div>')
                                .css({
                                    marginTop: '8px',
                                    fontWeight: 'bold'
                                })
                                .text(title)
                                .appendTo($data);
                            $('<div>')
                                .text(Ox.formatDate(data[id], '%B %e, %Y'))
                                .appendTo($data);
                        }
                    });

                    if (data.mediastate == 'available') {
                        renderShareButton().appendTo($data);
                    }

                    $('<div>').css({height: '16px'}).appendTo($data);

                }

            });

            function editMetadata(key, value) {
                var edit = Ox.extend(
                    {id: !isMultiple ? data.id : ui.listSelection},
                    key,
                    Ox.contains(arrayKeys, key) ? splitValue(value, key) : value
                );
                if (!Ox.isEqual(edit[key], data[key])) {
                    data[key] = edit[key];
                    oml.api.edit(edit, function(result) {
                        if (!isMultiple || ui.updateResults) {
                            Ox.Request.clearCache();
                            if (Ox.contains(['title', 'author', 'description'], key)) {
                                oml.$ui.info.updateElement();
                            }
                            if (ui.showFilters) {
                                oml.$ui.filters.forEach(function($filter) {
                                    $filter.reloadList(true);
                                });
                            }
                            oml.$ui.list.value(
                                result.data.id, key, result.data[key]
                            );
                            oml.$ui.browser.value(
                                result.data.id, key, result.data[key]
                            );
                        }
                        that.updateElement(result.data, [$data]);
                        that.triggerEvent('change', Ox.extend({}, key, value));
                    });
                }
            }

        });

    };

    if (!externalData) {
        ui.item && that.updateElement(ui.item);
    } else if (!isMultiple) {
        that.updateElement(externalData, [$icon, $info]);
    } else {
        that.updateElement(externalData, [$info]);
    }

    that.bindEvent({
        mousedown: function() {
            setTimeout(function() {
                !Ox.Focus.focusedElementIsInput() && that.gainFocus();
            });
        }
    })

    return that;

};