<template>
    <div class="playlist-editor">
        <div class="columns">
            <div class="column">
                <slot name="title" />
            </div>
            <div class="column has-text-right">
                <div class="float-right field has-addons">
                    <p class="control">
                        <a :class="['button','p-2', page == Page.Text ? 'is-primary' : 'is-light']"
                                @click="page = Page.Text">
                            <span class="icon is-small">
                                <i class="fa fa-pencil"></i>
                            </span>
                            <span>Texte</span>
                        </a>
                    </p>
                    <p class="control">
                        <a :class="['button','p-2', page == Page.List ? 'is-primary' : 'is-light']"
                                @click="page = Page.List">
                            <span class="icon is-small">
                                <i class="fa fa-list"></i>
                            </span>
                            <span>Liste</span>
                        </a>
                    </p>
                </div>
            </div>
        </div>
        <slot name="top" :set="set" :columns="columns" :items="items"/>
        <section class="page" v-show="page == Page.Text">
            <textarea ref="textarea" class="is-fullwidth is-size-6" rows="20"
                @change="updateList"
            />

        </section>
        <section class="page" v-show="page == Page.List">
            <a-rows :set="set" :columns="columns" :labels="labels"
                    :allow-create="true"
                    :orderable="true" @move="listItemMove" @colmove="columnMove"
                    @cell="onCellEvent">
                <template v-for="[name,slot] of rowsSlots" :key="slot"
                        v-slot:[slot]="data">
                    <slot v-if="name != 'row-tail'" :name="name" v-bind="data"/>
                </template>

                <template v-slot:row-tail="data">
                    <slot v-if="$slots['row-tail']" :name="row-tail" v-bind="data"/>
                    <td>
                        <a class="button is-danger is-outlined p-3 is-size-6"
                                @click="items.splice(data.row,1)"
                                :title="labels.remove_track"
                                :aria-label="labels.remove_track">
                            <span class="icon"><i class="fa fa-trash" /></span>
                        </a>
                    </td>
                </template>
            </a-rows>
        </section>

        <div class="mt-2">
            <div class="float-right">
                <a class="button is-warning p-2 ml-2"
                        @click="loadData({items: this.initData.items},true)">
                    <span class="icon"><i class="fa fa-rotate" /></span>
                    <span>{{ labels.discard_changes }}</span>
                </a>
                <a class="button is-primary p-2 ml-2" t-if="page == page.List"
                        @click="this.set.push(new this.set.model())">
                    <span class="icon"><i class="fa fa-plus"/></span>
                    <span>{{ labels.add_track }}</span>
                </a>
            </div>
            <div class="field is-inline-block is-vcentered mr-3">
                <label class="label is-inline mr-2"
                        style="vertical-align: middle">
                    Séparateur</label>
                <div class="control is-inline-block"
                        style="vertical-align: middle;">
                    <input type="text" ref="sep" class="input is-inline is-text-centered is-small"
                        style="max-width: 5em;"
                        v-model="separator" @change="updateList()"/>
                </div>
            </div>
            <div class="field is-inline-block is-vcentered mr-3">
                <label class="label is-inline mr-2"
                        style="vertical-align: middle">
                    {{ labels.columns }}</label>
                <table class="table is-bordered is-inline-block"
                        style="vertical-align: middle">
                    <tr>
                        <a-row :columns="columns" :item="labels"
                                @move="formatMove" :orderable="true">
                            <template v-slot:cell-after="{cell}">
                                <td style="cursor:pointer;" v-if="cell.col < columns.length-1">
                                    <span class="icon" @click="formatMove({from: cell.col, to: cell.col+1})"
                                        ><i class="fa fa-left-right"/>
                                    </span>
                                </td>
                            </template>
                        </a-row>
                    </tr>
                </table>
            </div>
            <div class="field is-vcentered is-inline-block"
                    v-if="settingsChanged">
                <a-action-button icon="fa fa-floppy-disk"
                        class="button control p-3 is-info" run-class="blink"
                        :url="settingsUrl" method="POST"
                        :data="settings"
                        :aria-label="labels.save_settings"
                        @done="settingsSaved()">
                    {{ labels.save_settings }}
                </a-action-button>
            </div>
        </div>
        <slot name="bottom" :set="set" :columns="columns" :items="items"/>
    </div>
</template>
<script>
import {dropRightWhile, cloneDeep, isEqual} from 'lodash'
import {Set} from '../model'
import Track from '../track'

import AActionButton from './AActionButton'
import ARow from './ARow.vue'
import ARows from './ARows.vue'

/// Page display
export const Page = {
    Text: 0, List: 1, Settings: 2,
}

export default {
    components: { AActionButton, ARow, ARows },
    props: {
        initData: Object,
        dataPrefix: String,
        labels: Object,
        settingsUrl: String,
        defaultColumns: {
            type: Array,
            default: () => ['artist', 'title', 'tags', 'album', 'year', 'timestamp']},
    },

    data() {
        const settings = {
            playlist_editor_columns: this.defaultColumns,
            playlist_editor_sep: ' -- ',
        }
        return {
            Page: Page,
            page: Page.Text,
            set: new Set(Track),
            extraData: {},
            settings,
            savedSettings: cloneDeep(settings),
        }
    },

    computed: {
        settingsChanged() {
            var k = Object.keys(this.savedSettings)
                          .findIndex(k => !isEqual(this.settings[k], this.savedSettings[k]))
            return k != -1
        },

        separator: {
            set(value) {
                this.settings.playlist_editor_sep = value
                if(this.page == Page.List)
                    this.updateInput()
            },
            get() { return this.settings.playlist_editor_sep }
        },

        columns: {
            set(value) {
                var cols = value.filter(x => x in this.defaultColumns)
                var left = this.defaultColumns.filter(x => !(x in cols))
                value = cols.concat(left)
                this.settings.playlist_editor_columns = value
            },
            get() {
                return this.settings.playlist_editor_columns
            }
        },

        items() {
            return this.set.items
        },

        rowsSlots() {
            return Object.keys(this.$slots)
                .filter(x => x.startsWith('row-') || x.startsWith('rows-'))
                .map(x => [x, x.startsWith('rows-') ? x.slice(5) : x])
        },
    },

    methods: {
        onCellEvent(event) {
            switch(event.name) {
                case 'change': this.updateInput();
                               break;
            }
        },

        formatMove({from, to}) {
            const value = this.columns[from]
            this.settings.playlist_editor_columns.splice(from, 1)
            this.settings.playlist_editor_columns.splice(to, 0, value)
            if(this.page == Page.Text)
                this.updateList()
            else
                this.updateInput()
        },

        columnMove({from, to}) {
            const value = this.columns[from]
            this.columns.splice(from, 1)
            this.columns.splice(to, 0, value)
            this.updateInput()
        },

        listItemMove({from, to, set}) {
            set.move(from, to);
            this.updateInput()
        },

        updateList() {
            const items = this.toList(this.$refs.textarea.value)
            this.set.reset(items)
        },

        updateInput() {
            const input = this.toText(this.items)
            this.$refs.textarea.value = input
        },

        /**
         * From input and separator, return list of items.
         */
        toList(input) {
            var lines = input.split('\n')
            var items = []

            for(let line of lines) {
                line = line.trimLeft()
                if(!line)
                    continue

                var lineBits = line.split(this.separator)
                var item = {}
                for(var col in this.columns) {
                    if(col >= lineBits.length)
                        break
                    const attr = this.columns[col]
                    item[attr] = lineBits[col].trim()
                }
                item && items.push(item)
            }
            return items
        },

        /**
         * From items and separator return a string
         */
        toText(items) {
            const sep = ` ${this.separator.trim()} `
            const lines = []
            for(let item of items) {
                if(!item)
                    continue
                var line = []
                for(var col of this.columns)
                    line.push(item.data[col] || '')
                line = dropRightWhile(line, x => !x || !('' + x).trim())
                line = line.join(sep).trimRight()
                lines.push(line)
            }
            return lines.join('\n')
        },


        _data_key(key) {
            key = key.slice(this.dataPrefix.length)
            try {
                var [index, attr] = key.split('-', 1)
                return [Number(index), attr]
            }
            catch(err) {
                return [null, key]
            }
        },

        //! Update saved settings from this.settings
        settingsSaved(settings=null) {
            if(settings !== null)
                this.settings = settings
            this.savedSettings = cloneDeep(this.settings)
        },

        /**
         * Load initial data
         */
        loadData({items=[], settings=null}, reset=false) {
            if(reset) {
                this.set.items = []
            }
            for(var index in items)
                this.set.push(cloneDeep(items[index]))
            if(settings)
                this.settingsSaved(settings)
            this.updateInput()
         },
    },

    watch: {
        initData(val) {
            this.loadData(val)
        },
    },

    mounted() {
        this.initData && this.loadData(this.initData)
        this.page = this.items.length ? Page.List : Page.Text
    },
}
</script>
