/* Copyright 2016 Software Freedom Conservancy Inc.
 * Copyright 2017 Jens Georg <mail@jensge.org>
 *
 * This software is licensed under the GNU LGPL (version 2.1 or later).
 * See the COPYING file in this distribution.
 */

public interface WelcomeServiceEntry : GLib.Object {
    public abstract string get_service_name();

    public abstract void execute();
}

public class WelcomeDialog : Gtk.Dialog {
    Gtk.CheckButton hide_button;
    Gtk.CheckButton? system_pictures_import_check = null;
    Gtk.CheckButton[] external_import_checks = new Gtk.CheckButton[0];
    WelcomeServiceEntry[] external_import_entries = new WelcomeServiceEntry[0];
    Gtk.Label secondary_text;
    Gtk.Label instruction_header;
    Gtk.Box import_content;
    Gtk.Box import_action_checkbox_packer;
    Gtk.Box external_import_action_checkbox_packer;
    bool import_content_already_installed = false;
    bool ok_clicked = false;
    GLib.MainLoop loop;

    public WelcomeDialog(Gtk.Window owner) {
        Object(use_header_bar : Resources.use_header_bar());
        bool show_system_pictures_import = is_system_pictures_import_possible();
        Gtk.Widget ok_button = add_button(Resources.OK_LABEL, Gtk.ResponseType.CLOSE);
        set_default_response(Gtk.ResponseType.CLOSE);

        set_title(_("Welcome!"));
        set_resizable(false);
        set_transient_for(owner);

        Gtk.Label primary_text = new Gtk.Label("");
        primary_text.set_markup(
            "<span size=\"large\" weight=\"bold\">%s</span>".printf(_("Welcome to Shotwell!")));
        primary_text.xalign = 0.0f;
        primary_text.yalign = 0.5f;
        secondary_text = new Gtk.Label("");
        secondary_text.set_markup("<span weight=\"normal\">%s</span>".printf(
            _("To get started, import photos in any of these ways:")));
        secondary_text.xalign = 0.0f;
        secondary_text.yalign = 0.5f;
        var image = new Gtk.Image.from_icon_name ("shotwell");

        Gtk.Box header_text = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
        header_text.append(primary_text);
        header_text.append(secondary_text);

        Gtk.Box header_content = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 12);
        header_content.append(image);
        header_content.append(header_text);

        Gtk.Label instructions = new Gtk.Label("");
        string indent_prefix = "   "; // we can't tell what the indent prefix is going to be so assume we need one

        instructions.set_markup(((indent_prefix + "&#8226; %s\n") + (indent_prefix + "&#8226; %s\n")
            + (indent_prefix + "&#8226; %s")).printf(
            _("Choose “Import From Folder” from the File menu"),
            _("Drag and drop photos onto the Shotwell window"),
            _("Connect a camera to your computer and import")));
        instructions.xalign = 0.0f;
        instructions.yalign = 0.5f;

        import_action_checkbox_packer = new Gtk.Box(Gtk.Orientation.VERTICAL, 2);

        external_import_action_checkbox_packer = new Gtk.Box(Gtk.Orientation.VERTICAL, 2);
        import_action_checkbox_packer.append(external_import_action_checkbox_packer);

        if (show_system_pictures_import) {
            system_pictures_import_check = new Gtk.CheckButton.with_mnemonic(
                _("_Import photos from your %s folder").printf(
                get_display_pathname(AppDirs.get_import_dir())));
            import_action_checkbox_packer.append(system_pictures_import_check);
            system_pictures_import_check.set_active(true);
        }

        instruction_header = new Gtk.Label(
            _("You can also import photos in any of these ways:"));
        instruction_header.xalign = 0.0f;
        instruction_header.yalign = 0.5f;
        instruction_header.set_margin_top(20);

        Gtk.Box content = new Gtk.Box(Gtk.Orientation.VERTICAL, 16);
        content.append(header_content);
        import_content = new Gtk.Box(Gtk.Orientation.VERTICAL, 2);
        content.append(import_content);
        content.append(instructions);

        hide_button = new Gtk.CheckButton.with_mnemonic(_("_Don’t show this message again"));
        hide_button.set_active(true);
        content.append(hide_button);
        content.halign = Gtk.Align.FILL;
        content.valign = Gtk.Align.FILL;
        content.hexpand = false;
        content.vexpand = false;
        content.margin_top = 12;
        content.margin_bottom = 0;
        content.margin_start = 12;
        content.margin_end = 12;

        ((Gtk.Box) get_content_area()).append(content);

        ok_button.grab_focus();

        install_import_content();
    }

    private void install_import_content() {
        if (
            (external_import_checks.length > 0 || system_pictures_import_check != null) &&
            (import_content_already_installed == false)
        ) {
            secondary_text.set_markup("");
            import_content.append(import_action_checkbox_packer);
            import_content.append(instruction_header);
            import_content_already_installed = true;
        }
    }

    public void install_service_entry(WelcomeServiceEntry entry) {
        debug("WelcomeDialog: Installing service entry for %s".printf(entry.get_service_name()));
        external_import_entries += entry;
        Gtk.CheckButton entry_check = new Gtk.CheckButton.with_label(
            _("Import photos from your %s library").printf(entry.get_service_name()));
        external_import_checks += entry_check;
        entry_check.set_active(true);
        external_import_action_checkbox_packer.append(entry_check);
        install_import_content();
    }

    /**
     * Connected to the 'response' signal.  This is part of a workaround
     * for the fact that run()-ning this dialog can interfere with displaying
     * images from a camera; please see #4997 for details.
     */
    private void on_dismiss(int resp) {
        if (resp == Gtk.ResponseType.CLOSE) {
            ok_clicked = true;
        }
        set_visible(false);
        loop.quit();
    }

    public bool execute(out WelcomeServiceEntry[] selected_import_entries, out bool do_system_pictures_import) {
        // it's unsafe to call run() here - it interferes with displaying
        // images from a camera - so we process the dialog ourselves.
        response.connect(on_dismiss);
        present();

        // this will block the thread we're in until a matching call
        // to main_quit() is encountered; this happens when either the window
        // is closed or OK is clicked.

        loop = new MainLoop();
        loop.run();

        // at this point, the inner main loop will have been exited.
        // we've got the response, so we don't need this signal anymore.
        response.disconnect(on_dismiss);

        bool ok = ok_clicked;
        bool show_dialog = true;

        if (ok)
            show_dialog = !hide_button.get_active();

        // Use a temporary variable as += cannot be used on parameters
        WelcomeServiceEntry[] result = new WelcomeServiceEntry[0];
        for (int i = 0; i < external_import_entries.length; i++) {
            if (external_import_checks[i].get_active() == true)
                result += external_import_entries[i];
        }
        selected_import_entries = result;
        do_system_pictures_import =
            (system_pictures_import_check != null) ? system_pictures_import_check.get_active() : false;

        destroy();

        return show_dialog;
    }

    private static bool is_system_pictures_import_possible() {
        File system_pictures = AppDirs.get_import_dir();
        if (!system_pictures.query_exists(null))
            return false;

        if (!(system_pictures.query_file_type(FileQueryInfoFlags.NONE, null) == FileType.DIRECTORY))
            return false;

        try {
            FileEnumerator syspics_child_enum = system_pictures.enumerate_children("standard::*",
                FileQueryInfoFlags.NONE, null);
            return (syspics_child_enum.next_file(null) != null);
        } catch (Error e) {
            return false;
        }
    }
}
