
define([
    'jquery',
    'base/js/utils',
    './common',
    './models',
], function($, utils, common, models) {
    "use strict";

    function action_start(btn) {
        var $btn = $(btn);
        $btn.focus();

        var $icon = $btn.find('i');
        var old_classes = $icon.attr('class');
        $icon.attr('class', 'fa fa-spinner fa-spin');
        return old_classes;
    }

    function action_end(btn, old_classes) {
        var $btn = $(btn);
        $btn.blur();
        $btn.find('i').attr('class', old_classes);
    }

    var ListView = {
        selector:  null,
        model:     null,
        columns:   [],      // e.g., [{ heading: 'Name', attr: 'name', width: 3 }]
        label:     'item',
        selectable: true,
        transforms: {},
        bindings:   {},

        init: function() {
            this.create_header();
            this.bind();
        },

        bind: function() {
            var $root = $(this.selector);

            $.each(this.bindings, function(selector, callback) {
                $root.find(selector).click(callback);
            });

            $root.find("button[title]").tooltip({
                container: "body",
                placement: "top"
            });
        },

        update_label: function(count) {
            $(this.selector).find('.toolbar_info').text(common.pluralize(count, this.label));
        },

        create_header: function(count) {
            var $header = $(this.selector).find('.list_header');
            $header.empty();

            $.each(this.columns, function(index, column) {
                $('<div/>')
                    .addClass('col-xs-' + column.width)
                    .text(column.heading)
                    .appendTo($header);
            });
        },

        refresh: function(data) {
            var that = this;
            var $root = $(this.selector);

            this.update_label(data.length);
            var $body = $root.find('.list_body');
            $body.empty();

            $.each(data, function(index, row) {
                var $row = $('<div/>')
                    .addClass('list_item')
                    .addClass('row')
                    .data('data', row);

                $.each(that.columns, function(index, column) {
                    var $cell = $('<div/>')
                        .addClass('col-xs-' + column.width);

                    var xform = that.transforms[column.attr];
                    if(xform) {
                        $cell.append(xform(row, $row));
                    }
                    else {
                        // Default is to stuff text in the div
                        $cell.text(row[column.attr]);
                    }

                    // Create selection checkbox, if needed
                    if(that.selectable && index === 0) {
                        var selected_box = $('<input/>')
                            .attr('type', 'checkbox')
                            .attr('title', 'Click to select')
                            .addClass('flush-left')
                            .click(function() { row.selected = ! row.selected; })
                            .prependTo($cell);
                    }

                    $row.append($cell);
                });

                $body.append($row);
            });
        }
    }

    var EnvView = Object.create(ListView);

    function new_env_prompt(callback) {
        var input = $('<input id="env_name" name="name"/>');
        var dialogform = $('<div/>').attr('title', 'Create New Environment').append(
            $('<form class="new_env_form"/>').append(
                $('<fieldset/>')
                .append($('<label for="env_name">Name:</label>'))
                .append(input)
                .append($('<label for="env_type">Type:</label>'))
                .append($('<select id="env_type" name="type">' +
                                '<option value="python2">Python 2</option>' +
                                '<option selected value="python3">Python 3</option>' +
                                '<option value="r">R</option>' +
                           '</select>'))
            )
        );

        function ok() {
            callback($('#env_name').val(), $('#env_type').val());
        }

        common.confirm('New Environment', dialogform, 'Create', ok, input);
    }

    $.extend(EnvView, {
        selector:   '#environments',
        label:      'Conda environment',
        selectable: false,
        model:      models.environments,
        columns:    [
            { heading: 'Action',    attr: '_action',    width: 1 },
            { heading: 'Name',      attr: 'name',       width: 3 },
            { heading: 'Default?',  attr: 'is_default', width: 1 },
            { heading: 'Directory', attr: 'dir',        width: 7 },
        ],

        transforms: {
            name: function(row) {
                return common.link('#', row.name)
                    .click(function() {
                        models.environments.select(row)
                    });
            },

            is_default: function(row) {
                return $('<div class="default_col">').append(common.icon(row.is_default ? 'check' : ''));
            },

            _action: function(row, $row) {
                // This is a pseudo-attribute

                function ActionMessage(msg) {
                    var $replacement = $('<div class="inprogress"/>').text(msg);
                    $row.find('.action_col').replaceWith($replacement);
                }

                return $('<span class="action_col"/>')
                    .addClass('btn-group')
                    .append(common.link(models.environments.export(row), common.icon('external-link')))
                    .append(common.icon('copy').click(function () {
                        common.prompt('Clone Environment', 'Create a copy of "' + row.name + '"', 'New name:', 'Clone', function(new_name) {
                            ActionMessage('Cloning...');
                            models.environments.clone(row, new_name);
                        });
                    }))
                    .append(common.icon('trash-o').click(function () {
                        var msg = 'Are you sure you want to permanently delete environment "' + row.name + '" ?';
                        common.confirm('Delete Environment', msg, 'Delete', function() {
                            ActionMessage('Deleting...');

                            // disable environment name link
                            var $link = $row.find('a').first();
                            $link.replaceWith($link.text());

                            models.environments.remove(row);
                        });
                    }));
            }
        },

        bindings: {
            '#new_env': function() {
                var btn = this;

                new_env_prompt(function(name, type) {
                    var btn_state = action_start(btn);
                    models.environments.create(name, type).then(function() {
                        action_end(btn, btn_state);
                    });
                });
            },
            '#refresh_env_list': function() {
                var btn = this;
                var btn_state = action_start(btn);

                models.environments.load().then(function() {
                    action_end(btn, btn_state);
                });
            },
        }
    });

    var AvailView = Object.create(ListView);

    $.extend(AvailView, {
        selector:   '#available_packages',
        label:      'available package',

        columns:    [
            { heading: 'Name',     attr: 'name',    width: 5 },
            { heading: 'Version',  attr: 'version', width: 2 },
            { heading: 'Channel',  attr: 'channel', width: 5 }
        ],

        bind: function() {
            ListView.bind.call(this);

            var that = this;
            var $box = $('#searchbox');

            $box.keyup(function() {
                that.filter($box.val());
            });
        },

        refresh: function(data) {
            ListView.refresh.call(this, data);

            var $box = $('#searchbox');
            this.filter($box.val());
        },

        bindings: {
            '#refresh_avail_list': function() {
                var btn = this;
                var btn_state = action_start(btn);

                models.available.load().then(function() {
                    action_end(btn, btn_state);
                });
            },

            '#install': function() {
                var btn = this;
                var msg = 'Are you sure you want to install ' +
                            common.pluralize(models.available.get_selection().length, 'package') +
                            ' into the environment "' + models.environments.selected.name + '" ?';

                common.confirm('Install Packages', msg, 'Install', function() {
                    var btn_state = action_start(btn);
                    models.available.conda_install().then(function() {
                        action_end(btn, btn_state);
                    });
                });
            }
        },

        filter: function(query) {
            var count = 0;

            $(this.selector).find('.list_item').each(function(index, elem) {
                var $elem = $(elem);

                if($elem.data('data').name.indexOf(query) === -1) {
                    $elem.hide();
                }
                else {
                    $elem.show();
                    count++;
                }
            });

            this.update_label(count);
        }
    });

    var InstalledView = Object.create(ListView);

    $.extend(InstalledView, {
        selector:   '#installed_packages',
        label:      'installed package',

        columns:    [
            { heading: 'Name',      attr: 'name',      width: 5 },
            { heading: 'Version',   attr: 'version',   width: 2 },
            { heading: 'Build',     attr: 'build',     width: 2 },
            { heading: 'Available', attr: 'available', width: 3 }
        ],

        update_label: function(count) {
            $(this.selector)
                .find('.toolbar_info')
                .text(common.pluralize(count, this.label) +
                    ' in environment "' + models.environments.selected.name + '"');
        },

        bindings: {
            '#refresh_pkg_list': function() {
                var btn = this;
                var btn_state = action_start(btn);

                models.installed.load().then(function() {
                    action_end(btn, btn_state);
                });
            },

            '#check_update': function() {
                var btn = this;
                var btn_state = action_start(btn);

                models.installed.conda_check_updates().then(function() {
                    action_end(btn, btn_state);
                });
            },

            '#update_pkgs': function() {
                var btn = this;
                var count = models.installed.get_selection().length;
                var packages = 'ALL packages';
                if(count > 0) {
                    packages = common.pluralize(count, 'package');
                }
                var msg = 'Are you sure you want to update ' + packages +
                            ' in the environment "' + models.environments.selected.name + '" ?';

                common.confirm('Update Packages', msg, 'Update', function() {
                    var btn_state = action_start(btn);
                    models.installed.conda_update().then(function() {
                        action_end(btn, btn_state);
                    });
                });
            },

            '#remove_pkgs': function() {
                var btn = this;
                var count = models.installed.get_selection().length;

                if(count === 0) {
                    return;
                }
                var msg = 'Are you sure you want to remove ' +
                            common.pluralize(count, 'package') +
                            ' from the environment "' + models.environments.selected.name + '" ?';

                common.confirm('Remove Packages', msg, 'Remove', function() {
                    var btn_state = action_start(btn);
                    models.installed.conda_remove().then(function() {
                        action_end(btn, btn_state);
                    });
                });
            }
        },
    });

    return {
        'EnvView':       EnvView,
        'AvailView':     AvailView,
        'InstalledView': InstalledView
    };
});
