package Padre::Plugin::WebGUI::Assets;

use 5.008;
use strict;
use warnings;
use Padre::Current ();
use Padre::Util    ();
use Padre::Wx      ();
use base 'Wx::TreeCtrl';

# generate fast accessors
use Class::XSAccessor getters => {
    plugin    => 'plugin',
    connected => 'connected',
    url       => 'url',
};

# constructor
sub new {
    my $class  = shift;
    my $plugin = shift;

    my $self = $class->SUPER::new( $plugin->main->right, -1, Wx::wxDefaultPosition, Wx::wxDefaultSize,
        Wx::wxTR_HIDE_ROOT | Wx::wxTR_SINGLE | Wx::wxTR_HAS_BUTTONS | Wx::wxTR_LINES_AT_ROOT | Wx::wxBORDER_NONE );

    $self->{plugin} = $plugin;

    # Register event handlers..
    Wx::Event::EVT_TREE_ITEM_ACTIVATED(
        $self, $self,
        sub {
            $self->on_tree_item_activated( $_[1] );
        },
    );

    $self->Hide;

    # Create image list
    my $imglist = Wx::ImageList->new( 16, 16 );
    $self->AssignImageList($imglist);
    $imglist->Add( Padre::Wx::Icon::find('status/padre-plugin') );

    return $self;
}

# accessors
sub right         { $_[0]->GetParent }
sub main          { $_[0]->GetGrandParent }
sub gettext_label { Wx::gettext('Asset Tree') }
sub clear         { $_[0]->DeleteAllItems }

sub update_gui {
    my $self = shift;
    if ( $self->connected ) {
        $self->update_gui_connected;
    }
    else {
        $self->update_gui_disconnected;
    }
}

sub update_gui_disconnected {
    my $self = shift;

    $self->{connected} = 0;

    $self->Freeze;
    $self->clear;

    my $root = $self->AddRoot( Wx::gettext('Asset Tree'), -1, -1, Wx::TreeItemData->new('') );
    my $connect = $self->AppendItem( $root, 'Connect', -1, -1, Wx::TreeItemData->new( { connect => 1 } ), );
    $self->SetItemTextColour( $connect, Wx::Colour->new( 0x00, 0x00, 0x7f ) );
    $self->SetItemImage( $connect, 0 );
    $self->GetBestSize;

    $self->Thaw;
}

sub update_gui_connected {
    my $self = shift;

    $self->{connected} = 1;

    # Show loading indicator
    $self->Freeze;
    $self->clear;

    my $tmp_root = $self->AddRoot( Wx::gettext('Asset Tree'), -1, -1, Wx::TreeItemData->new('') );
    my $status = $self->AppendItem( $tmp_root, 'Loading..', -1, -1, Wx::TreeItemData->new( { loading => 1 } ), );
    $self->SetItemTextColour( $status, Wx::Colour->new( 0x00, 0x00, 0x7f ) );
    $self->SetItemImage( $status, 0 );
    $self->GetBestSize;

    $self->Thaw;

    # Force window update
    $self->Update;

    # Now actually connect..
    $self->Freeze;
    $self->clear;

    my $root = $self->AddRoot( Wx::gettext('Asset Tree'), -1, -1, Wx::TreeItemData->new('') );
    my $refresh = $self->AppendItem( $root, 'Refresh', -1, -1, Wx::TreeItemData->new( { refresh => 1 } ), );
    $self->SetItemTextColour( $refresh, Wx::Colour->new( 0x00, 0x00, 0x7f ) );
    $self->SetItemImage( $refresh, 0 );

    if ( my $assets = $self->build_asset_tree ) {
        update_treectrl( $self, $assets, $root );

        # Register right-click event handler
        Wx::Event::EVT_TREE_ITEM_RIGHT_CLICK( $self, $self, \&on_tree_item_right_click, );

        $self->GetBestSize;
        $self->Thaw;
    }
    else {

        # Reset back to disconnected state
        $self->GetBestSize;
        $self->Thaw;
        $self->update_gui_disconnected;
    }
}

# generate the list of assets
# todo - make this lazy-load for better performance
sub build_asset_tree {
    my $self = shift;

    # Create a user agent object
    use LWP::UserAgent;
    my $ua       = LWP::UserAgent->new;
    my $response = $ua->get( $self->url . '?op=padre&func=list' );
    unless ( $response->header('Padre-Plugin-WebGUI') ) {
        $self->main->error(
            "The server does not appear to have the Padre::Plugin::WebGUI content handler installed");
        return;
    }
    if ( !$response->is_success ) {
        $self->main->error( "The server said:\n" . $response->status_line );
        return;
    }

    my $assets = $response->content;

    # Padre::Util::debug($assets);

    use JSON;
    $assets = eval { from_json($assets) };
    if ($@) {
        Padre::Util::debug($@);
        $self->main->error("The server sent an invalid response, please try again (and check the logs)");
        return;
    }
    else {
        return $assets;
    }
}

sub edit_asset {
    my $self = shift;
    my $item = shift;

    # Create new editor tab
    my $main = $self->main;
    $main->on_new();
    my $editor = $main->current->editor or return;
    my $doc = $editor->{Document};

    # Set WebGUI Asset mime-type and rebless
    my %registered_documents = $self->plugin->registered_documents;
    my $mimetype             = lc $item->{className};
    $mimetype =~ s/.*:://;
    $mimetype = "application/x-webgui-$mimetype";

    # Fall-back to generic 'asset' mime-type
    $mimetype = "application/x-webgui-asset" unless $registered_documents{$mimetype};
    Padre::Util::debug("Using mimetype: $mimetype for $item->{className}");
    $doc->set_mimetype($mimetype);

    # Rebless
    $doc->editor->padre_setup;
    $doc->rebless;

    return unless $doc->isa('Padre::Document::WebGUI::Asset');

    # Load asset
    $doc->load_asset( $item->{assetId}, $self->url );

    # Fake-save tab so that it isn't in the unsaved state
    my $id   = $main->find_id_of_editor($editor);
    my $page = $main->notebook->GetPage($id);
    $page->SetSavePoint;
    $main->refresh;
}

sub on_tree_item_right_click {
    my ( $self, $event ) = @_;

    my $showMenu = 0;
    my $menu     = Wx::Menu->new;
    my $item     = $self->GetPlData( $event->GetItem );

    if ( defined $item ) {
        my $submenu;

        $submenu = $menu->Append( -1, Wx::gettext("Details..") );
        Wx::Event::EVT_MENU(
            $self, $submenu,
            sub {
                $self->on_tree_item_activated( $event, { action => 'details' } );
            },
        );

        $submenu = $menu->Append( -1, Wx::gettext("Edit") );
        Wx::Event::EVT_MENU(
            $self, $submenu,
            sub {
                $self->edit_asset($item);
            },
        );

        $showMenu++;
    }

    if ( $showMenu > 0 ) {
        my $x = $event->GetPoint->x;
        my $y = $event->GetPoint->y;
        $self->PopupMenu( $menu, $x, $y );
    }

    return;
}

# event handler for item activation
sub on_tree_item_activated {
    my ( $self, $event, $opts ) = @_;
    $opts ||= {};

    # Get the target item
    my $item = $self->GetPlData( $event->GetItem );
    return if not defined $item;

    if ( $item->{connect} ) {
        my $url
            = $self->main->prompt(
            'Enter a URL to connect to, for example: http://admin:123qwe@dev.localhost.localdomain',
            'Connect To Server', 'wg_url' );
        return unless $url;
        $self->{url} = $url;
        $self->update_gui_connected;
        return;
    }

    elsif ( $item->{refresh} ) {
        $self->update_gui_connected;
        return;
    }

    elsif ( $opts->{action} eq 'details' ) {
        my $str = q{};
        for my $key ( sort keys %$item ) {
            $str .= qq{$key:\t\t $item->{$key}\n};
        }
        $self->main->error($str);
    }

    else {

        # Default event is double-click
        $self->edit_asset($item);
    }

    return;
}

my $image_lookup;

sub get_item_image {
    my $self = shift;
    my $icon = shift;

    $icon =~ s{.*/}{};
    my $imglist = $self->GetImageList;
    if ( !$image_lookup->{$icon} ) {
        my $index
            = $imglist->Add(
            Wx::Bitmap->new( $self->plugin->plugin_directory_share . "/icons/16x16/$icon", Wx::wxBITMAP_TYPE_GIF )
            );
        $image_lookup->{$icon} = $index;
    }
    return $image_lookup->{$icon} || 0;
}

sub update_treectrl {
    my ( $self, $items, $parent ) = @_;

    foreach my $item ( @{$items} ) {
        my $node = $self->AppendItem( $parent, $item->{menuTitle}, -1, -1, Wx::TreeItemData->new( {%$item} ), );
        $self->SetItemTextColour( $node, Wx::Colour->new( 0x00, 0x00, 0x7f ) );
        $self->SetItemImage( $node, $self->get_item_image( $item->{icon} ) );

        # Recurse, adding children to $node
        update_treectrl( $self, $item->{children}, $node );
    }

    return;
}

1;

# Copyright 2009 Patrick Donelan
# LICENSE
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl 5 itself.
