'use strict';

const api = require('../api.js');
const events = require('../events.js');
const misc = require('../util/misc.js');
const views = require('../util/views.js');
const Note = require('../models/note.js');
const Point = require('../models/point.js');
const TagInputControl = require('./tag_input_control.js');
const PoolInputControl = require('./pool_input_control.js');
const ExpanderControl = require('../controls/expander_control.js');
const FileDropperControl = require('../controls/file_dropper_control.js');

const template = views.getTemplate('post-edit-sidebar');

class PostEditSidebarControl extends events.EventTarget {
    constructor(hostNode, post, postContentControl, postNotesOverlayControl) {
        super();
        this._hostNode = hostNode;
        this._post = post;
        this._postContentControl = postContentControl;
        this._postNotesOverlayControl = postNotesOverlayControl;
        this._newPostContent = null;

        this._postNotesOverlayControl.switchToPassiveEdit();

        views.replaceContent(this._hostNode, template({
            post: this._post,
            enableSafety: api.safetyEnabled(),
            hasClipboard: document.queryCommandSupported('copy'),
            canEditPostSafety: api.hasPrivilege('posts:edit:safety'),
            canEditPostSource: api.hasPrivilege('posts:edit:source'),
            canEditPostTags: api.hasPrivilege('posts:edit:tags'),
            canEditPostRelations: api.hasPrivilege('posts:edit:relations'),
            canEditPostNotes: api.hasPrivilege('posts:edit:notes') &&
                post.type !== 'video' &&
                post.type !== 'flash',
            canEditPostFlags: api.hasPrivilege('posts:edit:flags'),
            canEditPostContent: api.hasPrivilege('posts:edit:content'),
            canEditPostThumbnail: api.hasPrivilege('posts:edit:thumbnail'),
            canEditPoolPosts: api.hasPrivilege('pools:edit:posts'),
            canCreateAnonymousPosts: api.hasPrivilege('posts:create:anonymous'),
            canDeletePosts: api.hasPrivilege('posts:delete'),
            canFeaturePosts: api.hasPrivilege('posts:feature'),
            canMergePosts: api.hasPrivilege('posts:merge'),
        }));

        new ExpanderControl(
            'post-info',
            'Basic info',
            this._hostNode.querySelectorAll('.safety, .relations, .flags, .post-source'));
        this._tagsExpander = new ExpanderControl(
            'post-tags',
            `Tags (${this._post.tags.length})`,
            this._hostNode.querySelectorAll('.tags'));
        this._notesExpander = new ExpanderControl(
            'post-notes',
            'Notes',
            this._hostNode.querySelectorAll('.notes'));
        this._poolsExpander = new ExpanderControl(
            'post-pools',
            `Pools (${this._post.pools.length})`,
            this._hostNode.querySelectorAll('.pools'));
        new ExpanderControl(
            'post-content',
            'Content',
            this._hostNode.querySelectorAll('.post-content, .post-thumbnail'));
        new ExpanderControl(
            'post-management',
            'Management',
            this._hostNode.querySelectorAll('.management'));

        this._syncExpanderTitles();

        if (this._formNode) {
            this._formNode.addEventListener('submit', e => this._evtSubmit(e));
        }

        if (this._tagInputNode) {
            this._tagControl = new TagInputControl(
                this._tagInputNode, post.tags);
        }

        if (this._poolInputNode) {
            this._poolControl = new PoolInputControl(
                this._poolInputNode, post.pools);
        }

        if (this._contentInputNode) {
            this._contentFileDropper = new FileDropperControl(
                this._contentInputNode, {allowUrls: true,
                    lock: true,
                    urlPlaceholder: '...or paste an URL here.'});
            this._contentFileDropper.addEventListener('fileadd', e => {
                this._newPostContent = e.detail.files[0];
            });
            this._contentFileDropper.addEventListener('urladd', e => {
                this._newPostContent = e.detail.urls[0];
            });
        }

        if (this._thumbnailInputNode) {
            this._thumbnailFileDropper = new FileDropperControl(
                this._thumbnailInputNode, {lock: true});
            this._thumbnailFileDropper.addEventListener('fileadd', e => {
                this._newPostThumbnail = e.detail.files[0];
                this._thumbnailRemovalLinkNode.style.display = 'block';
            });
        }

        if (this._thumbnailRemovalLinkNode) {
            this._thumbnailRemovalLinkNode.addEventListener(
                'click', e => this._evtRemoveThumbnailClick(e));
            this._thumbnailRemovalLinkNode.style.display =
                this._post.hasCustomThumbnail ? 'block' : 'none';
        }

        if (this._addNoteLinkNode) {
            this._addNoteLinkNode.addEventListener(
                'click', e => this._evtAddNoteClick(e));
        }

        if (this._copyNotesLinkNode) {
            this._copyNotesLinkNode.addEventListener(
                'click', e => this._evtCopyNotesClick(e));
        }

        if (this._pasteNotesLinkNode) {
            this._pasteNotesLinkNode.addEventListener(
                'click', e => this._evtPasteNotesClick(e));
        }

        if (this._deleteNoteLinkNode) {
            this._deleteNoteLinkNode.addEventListener(
                'click', e => this._evtDeleteNoteClick(e));
        }

        if (this._featureLinkNode) {
            this._featureLinkNode.addEventListener(
                'click', e => this._evtFeatureClick(e));
        }

        if (this._mergeLinkNode) {
            this._mergeLinkNode.addEventListener(
                'click', e => this._evtMergeClick(e));
        }

        if (this._deleteLinkNode) {
            this._deleteLinkNode.addEventListener(
                'click', e => this._evtDeleteClick(e));
        }

        this._postNotesOverlayControl.addEventListener(
            'blur', e => this._evtNoteBlur(e));

        this._postNotesOverlayControl.addEventListener(
            'focus', e => this._evtNoteFocus(e));

        this._post.addEventListener(
            'changeContent', e => this._evtPostContentChange(e));

        this._post.addEventListener(
            'changeThumbnail', e => this._evtPostThumbnailChange(e));

        if (this._formNode) {
            const inputNodes = this._formNode.querySelectorAll(
                'input, textarea');
            for (let node of inputNodes) {
                node.addEventListener(
                    'change',
                    e => this.dispatchEvent(new CustomEvent('change')));
            }
            this._postNotesOverlayControl.addEventListener(
                'change',
                e => this.dispatchEvent(new CustomEvent('change')));
        }

        for (let eventType of ['add', 'remove']) {
            this._post.notes.addEventListener(eventType, e => {
                this._syncExpanderTitles();
            });
            this._post.pools.addEventListener(eventType, e => {
                this._syncExpanderTitles();
            });
        }

        this._tagControl.addEventListener(
            'change', e => {
                this.dispatchEvent(new CustomEvent('change'));
                this._syncExpanderTitles();
            });

        if (this._noteTextareaNode) {
            this._noteTextareaNode.addEventListener(
                'change', e => this._evtNoteTextChangeRequest(e));
        }

        this._poolControl.addEventListener(
            'change', e => {
                this.dispatchEvent(new CustomEvent('change'));
                this._syncExpanderTitles();
            });
    }

    _syncExpanderTitles() {
        this._notesExpander.title = `Notes (${this._post.notes.length})`;
        this._tagsExpander.title = `Tags (${this._post.tags.length})`;
        this._poolsExpander.title = `Pools (${this._post.pools.length})`;
    }

    _evtPostContentChange(e) {
        this._contentFileDropper.reset();
    }

    _evtPostThumbnailChange(e) {
        this._thumbnailFileDropper.reset();
    }

    _evtRemoveThumbnailClick(e) {
        e.preventDefault();
        this._thumbnailFileDropper.reset();
        this._newPostThumbnail = null;
        this._thumbnailRemovalLinkNode.style.display = 'none';
    }

    _evtFeatureClick(e) {
        e.preventDefault();
        if (confirm('Are you sure you want to feature this post?')) {
            this.dispatchEvent(new CustomEvent('feature', {
                detail: {
                    post: this._post,
                },
            }));
        }
    }

    _evtMergeClick(e) {
        e.preventDefault();
        this.dispatchEvent(new CustomEvent('merge', {
            detail: {
                post: this._post,
            },
        }));
    }

    _evtDeleteClick(e) {
        e.preventDefault();
        if (confirm('Are you sure you want to delete this post?')) {
            this.dispatchEvent(new CustomEvent('delete', {
                detail: {
                    post: this._post,
                },
            }));
        }
    }

    _evtNoteTextChangeRequest(e) {
        if (this._editedNote) {
            this._editedNote.text = this._noteTextareaNode.value;
        }
    }

    _evtNoteFocus(e) {
        this._editedNote = e.detail.note;
        this._addNoteLinkNode.classList.remove('inactive');
        this._deleteNoteLinkNode.classList.remove('inactive');
        this._noteTextareaNode.removeAttribute('disabled');
        this._noteTextareaNode.value = e.detail.note.text;
    }

    _evtNoteBlur(e) {
        this._evtNoteTextChangeRequest(null);
        this._addNoteLinkNode.classList.remove('inactive');
        this._deleteNoteLinkNode.classList.add('inactive');
        this._noteTextareaNode.blur();
        this._noteTextareaNode.setAttribute('disabled', 'disabled');
        this._noteTextareaNode.value = '';
    }

    _evtAddNoteClick(e) {
        e.preventDefault();
        if (e.target.classList.contains('inactive')) {
            return;
        }
        this._addNoteLinkNode.classList.add('inactive');
        this._postNotesOverlayControl.switchToDrawing();
    }

    _evtCopyNotesClick(e) {
        e.preventDefault();
        let textarea = document.createElement('textarea');
        textarea.style.position = 'fixed';
        textarea.style.opacity = '0';
        textarea.value = JSON.stringify([...this._post.notes].map(note => ({
            polygon: [...note.polygon].map(
                point => [point.x, point.y]),
            text: note.text,
        })));
        document.body.appendChild(textarea);
        textarea.select();

        let success = false;
        try {
            success = document.execCommand('copy');
        } catch (err) {
            // continue regardless of error
        }
        textarea.blur();
        document.body.removeChild(textarea);
        alert(success
            ? 'Notes copied to clipboard.'
            : 'Failed to copy the text to clipboard. Sorry.');
    }

    _evtPasteNotesClick(e) {
        e.preventDefault();
        const text = window.prompt(
            'Please enter the exported notes snapshot:');
        if (!text) {
            return;
        }
        const notesObj = JSON.parse(text);
        this._post.notes.clear();
        for (let noteObj of notesObj) {
            let note = new Note();
            for (let pointObj of noteObj.polygon) {
                note.polygon.add(new Point(pointObj[0], pointObj[1]));
            }
            note.text = noteObj.text;
            this._post.notes.add(note);
        }
    }

    _evtDeleteNoteClick(e) {
        e.preventDefault();
        if (e.target.classList.contains('inactive')) {
            return;
        }
        this._post.notes.remove(this._editedNote);
        this._postNotesOverlayControl.switchToPassiveEdit();
    }

    _evtSubmit(e) {
        e.preventDefault();
        this.dispatchEvent(new CustomEvent('submit', {
            detail: {
                post: this._post,

                safety: this._safetyButtonNodes.length ?
                    Array.from(this._safetyButtonNodes)
                        .filter(node => node.checked)[0]
                        .value.toLowerCase() :
                    undefined,

                flags: this._videoFlags,

                tags: this._tagInputNode ?
                    misc.splitByWhitespace(this._tagInputNode.value) :
                    undefined,

                pools: this._poolInputNode ?
                    misc.splitByWhitespace(this._poolInputNode.value) :
                    undefined,

                relations: this._relationsInputNode ?
                    misc.splitByWhitespace(this._relationsInputNode.value)
                        .map(x => parseInt(x)) :
                    undefined,

                content: this._newPostContent ?
                    this._newPostContent :
                    undefined,

                thumbnail: this._newPostThumbnail !== undefined ?
                    this._newPostThumbnail :
                    undefined,

                source: this._sourceInputNode ?
                    this._sourceInputNode.value :
                    undefined,
            },
        }));
    }

    get _formNode() {
        return this._hostNode.querySelector('form');
    }

    get _submitButtonNode() {
        return this._hostNode.querySelector('.submit');
    }

    get _safetyButtonNodes() {
        return this._formNode.querySelectorAll('.safety input');
    }

    get _tagInputNode() {
        return this._formNode.querySelector('.tags input');
    }

    get _poolInputNode() {
        return this._formNode.querySelector('.pools input');
    }

    get _loopVideoInputNode() {
        return this._formNode.querySelector('.flags input[name=loop]');
    }

    get _soundVideoInputNode() {
        return this._formNode.querySelector('.flags input[name=sound]');
    }

    get _videoFlags() {
        if (!this._loopVideoInputNode) {
            return undefined;
        }
        let ret = [];
        if (this._loopVideoInputNode.checked) {
            ret.push('loop');
        }
        if (this._soundVideoInputNode.checked) {
            ret.push('sound');
        }
        return ret;
    }

    get _relationsInputNode() {
        return this._formNode.querySelector('.relations input');
    }

    get _contentInputNode() {
        return this._formNode.querySelector('.post-content .dropper-container');
    }

    get _thumbnailInputNode() {
        return this._formNode.querySelector(
            '.post-thumbnail .dropper-container');
    }

    get _thumbnailRemovalLinkNode() {
        return this._formNode.querySelector('.post-thumbnail a');
    }

    get _sourceInputNode() {
        return this._formNode.querySelector('.post-source textarea');
    }

    get _featureLinkNode() {
        return this._formNode.querySelector('.management .feature');
    }

    get _mergeLinkNode() {
        return this._formNode.querySelector('.management .merge');
    }

    get _deleteLinkNode() {
        return this._formNode.querySelector('.management .delete');
    }

    get _addNoteLinkNode() {
        return this._formNode.querySelector('.notes .add');
    }

    get _copyNotesLinkNode() {
        return this._formNode.querySelector('.notes .copy');
    }

    get _pasteNotesLinkNode() {
        return this._formNode.querySelector('.notes .paste');
    }

    get _deleteNoteLinkNode() {
        return this._formNode.querySelector('.notes .delete');
    }

    get _noteTextareaNode() {
        return this._formNode.querySelector('.notes textarea');
    }

    enableForm() {
        views.enableForm(this._formNode);
    }

    disableForm() {
        views.disableForm(this._formNode);
    }

    clearMessages() {
        views.clearMessages(this._hostNode);
    }

    showSuccess(message) {
        views.showSuccess(this._hostNode, message);
    }

    showError(message) {
        views.showError(this._hostNode, message);
    }
}

module.exports = PostEditSidebarControl;