# -*- coding: utf-8 -*-

miquire :mui, 'skin'
miquire :addon, 'addon'
miquire :addon, 'settings'

Module.new do

  @tabclass = Class.new(Addon.gen_tabclass){
    def initialize(name, service, options = {})
      @page = 1
      options[:header] = Gtk::VBox.new(false, 0)
      super(name, service, options) end

    def suffix
      'のプロフィール' end

    def user
      @options[:user] end

    def on_create
      @appear_event = Plugin::create(:profile).add_event(:appear){ |res|
        unless timeline.destroyed?
          msgs = res.select{ |msg| msg[:user][:id] == user[:id] }
          timeline.add(msgs) if not msgs.empty? end }
      @service.call_api(:user_timeline, :user_id => user[:id],
                        :no_auto_since_id => true,
                        :count => 20){ |tl|
        Delayer.new{
          timeline.add(tl) unless timeline.destroyed? } if tl }
      @service.call_api(:list_user_followers, :user => user[:id]){ |res|
        if not(@notebook.destroyed?) and res
          followed_list_ids = res.map{|list| list['id'].to_i}
          locked = {}
          @list = Gtk::ListList.new{ |iter|
            if not locked[iter[1]]
              locked[iter[1]] = true
              flag = iter[0] # = !iter[0]
              @service.__send__(flag ? :delete_list_member : :add_list_member,
                                :list_id => iter[2]['id'],
                                :idname => @service.user,
                                :id => user[:id]){ |e, m|
                case(e)
                when :success
                  iter[0] = !flag if not(@list.destroyed?)
                when :exit
                  locked[iter[1]] = false
                end } end }
          @list.set_auto_get{ |list|
            followed_list_ids.include?(list['id'].to_i) }
          @notebook.append_page(@list.show_all,
                                Gtk::WebIcon.new(MUI::Skin.get("list.png"), 16, 16).show_all) end }
      header.closeup(profile).show_all
      super
      focus end

    def on_remove
      super
      Plugin::create(:profile).detach(:appear, @appear_event) end

    private

    def gen_main
      @timeline = Gtk::TimeLine.new
      @notebook = Gtk::Notebook.new.set_tab_pos(Gtk::POS_TOP).set_tab_border(0)
      @notebook.append_page(@timeline,
                            Gtk::WebIcon.new(MUI::Skin.get("timeline.png"), 16, 16).show_all)
      @header = (@options[:header] or Gtk::HBox.new)
      Gtk::VBox.new(false, 0).closeup(@header).add(@notebook) end

    def background_color
      style = Gtk::Style.new()
      style.set_bg(Gtk::STATE_NORMAL, 0xFF ** 2, 0xFF ** 2, 0xFF ** 2)
      style end

    def relation
      relationbox = Gtk::VBox.new(false, 0)
      if user[:idname] == @service.user
        relationbox.add(Gtk::Label.new('それはあなたです！'))
      else
        @service.call_api(:friendship,
                          :target_screen_name => user[:idname],
                          :source_screen_name => @service.user){ |res|
          if(res)
            res = res.first
            Delayer.new{
              unless(relationbox.destroyed?)
                relationbox.closeup(Gtk::Label.new("#{user[:idname]}はあなたをフォローしていま" +
                                                   if res[:followed_by] then 'す' else 'せん' end)).
                  closeup(followbutton(res[:user], res[:following])).
                  closeup(mutebutton(res[:user])).show_all end } end } end
      relationbox end

    def profile
      eventbox = Gtk::EventBox.new
      eventbox.signal_connect('visibility-notify-event'){
        eventbox.style = background_color
        false }
      eventbox.add(Gtk::VBox.new(false, 0).
                   closeup(toolbar).
                   add(Gtk::HBox.new(false, 16).
                       closeup(Gtk::WebIcon.new(user[:profile_image_url]).top).
                       add(Gtk::VBox.new(false, 0).add(main(eventbox)).add(relation)))) end

    def followbutton(user, following)
      btn = nil
      changer = lambda{ |new, widget|
        if new === nil
          following
        elsif new != following
          widget.sensitive = false
          @service.method(new ? :follow : :unfollow).call(user){ |event, msg|
            case event
            when :exit
              Plugin::call(new ? :followings_created : :followings_destroy, @service, [user])
              following = new
              Delayer.new{
                unless widget.destroyed?
                  widget.sensitive = true end } end } end }
      btn = Mtk::boolean(changer, 'フォロー') end

    def mutebutton(user)
      changer = lambda{ |new, widget|
        if new === nil
          UserConfig[:muted_users] and UserConfig[:muted_users].include?(user.idname)
        elsif new
          add_muted_user(user)
        else
          remove_muted_user(user)
        end
      }
      btn = Mtk::boolean(changer, 'ミュート')
    end

    def add_muted_user(user)
      type_strict user => User
      atomic{
        muted = (UserConfig[:muted_users] ||= []).melt
        muted << user.idname
        UserConfig[:muted_users] = muted } end

    def remove_muted_user(user)
      type_strict user => User
      atomic{
        muted = (UserConfig[:muted_users] ||= []).melt
        muted.delete(user.idname)
        UserConfig[:muted_users] = muted } end

    def toolbar
      container = Gtk::HBox.new(false, 0)
      close = Gtk::Button.new.add(Gtk::WebIcon.new(MUI::Skin.get('close.png'), 16, 16))
      close.signal_connect('clicked'){
        remove }
      container.closeup(close) end

    def main(window_parent)
      ago = (Time.now - (user[:created] or 1)).to_i / (60 * 60 * 24)
      tags = []
      text = "#{user[:idname]} #{user[:name]}\n"
      append = lambda{ |title, value|
        tags << ['_caption_style', text.strsize, title.strsize]
        text << "#{title} #{value}" }
      append.call "location", "#{user[:location]}\n" if user[:location]
      append.call  "web", "#{user[:url]}\n" if user[:url]
      append.call "bio", "#{user[:detail]}\n\n" if user[:detail]
      append.call "フォロー", "#{user[:friends_count]} / "
      append.call "フォロワー", "#{user[:followers_count]} / #{user[:statuses_count]}Tweets " +
        "(#{if ago == 0 then user[:statuses_count] else (user[:statuses_count].to_f / ago).round_at(2) end}/day)\n"
      append.call "since", "#{user[:created].strftime('%Y/%m/%d %H:%M:%S')}" if user[:created]
      body = Gtk::IntelligentTextview.new(text)
      body.buffer.create_tag('_caption_style',
                             'foreground_gdk' => Gdk::Color.new(0, 0x33 ** 2, 0x66 ** 2),
                             'weight' => Pango::FontDescription::WEIGHT_BOLD)
      tags << [tag_user_id_link(body), 0, user[:idname].size]
      tags.each{ |token|
        body.buffer.apply_tag(token[0], *body.buffer.get_range(*token[1..2])) }
      body.get_background = lambda{ background_color }
      body end

    private

    def tag_user_id_link(body)
      tag = body.buffer.create_tag('_user_id_link',
                                   'foreground' => 'blue',
                                   "underline" => Pango::UNDERLINE_SINGLE)
      tag.signal_connect('event'){ |this, textview, event, iter|
        result = false
        if(event.is_a?(Gdk::EventButton)) and
            (event.event_type == Gdk::Event::BUTTON_RELEASE) and
            not(textview.buffer.selection_bounds[2])
          if (event.button == 1)
            Gtk::openurl('http://twitter.com/#!/'+user[:idname]) end
        elsif(event.is_a?(Gdk::EventMotion))
          body.set_cursor(textview, Gdk::Cursor::HAND2) end
        result }
      tag end }

  def self.boot
    plugin = Plugin::create(:profile)
    plugin.add_event(:show_profile){ |service, user|
      makescreen(user, service) }
    plugin.add_event(:boot){ |service|
      set_contextmenu(plugin, service)
      Message::Entity.addlinkrule(:user_mentions, /(?:@|＠|〄)[a-zA-Z0-9_]+/){ |segment|
        idname = segment[:url].match(/^(?:@|＠|〄)?(.+)$/)[1]
        user = User.findbyidname(idname)
        if user
          makescreen(user, service)
        else
          Thread.new{
            user = service.scan(:user_show,
                                :no_auto_since_id => false,
                                :screen_name => idname)
            Delayer.new{ makescreen(user.first, service) } if user } end } }
    plugin.add_event_filter(:show_filter){ |messages|
      muted_users = UserConfig[:muted_users]
      if muted_users
        [messages.select{ |m| not muted_users.include?(m.idname) }]
      else
        [messages] end } end

  private

  def self.set_contextmenu(plugin, service)

    plugin.add_event_filter(:command){ |menu|
      menu[:show_profile] = {
        :slug => :show_profile,
        :name => 'ユーザについて',
        :show_face => lambda{ |m|
          u = if(m.message[:retweet])
                m.message[:retweet].user
              else
                m.message.user end
          "#{u[:idname]}(#{u[:name]})について".gsub(/_/, '__') },
        :condition => lambda{ |m| m.message.repliable? },
        :exec => lambda{ |m|
          user = if(m.is_a? User)
                   m
                 elsif(m.message[:retweet])
                   m.message[:retweet].user
                 else
                   m.message.user end
          makescreen(user, service) },
        :visible => true,
        :role => :message }
      [menu]
    }

    return

    plugin.add_event_filter(:contextmenu){ |menu|
      menu << [lambda{ |m, w|
                 if(nil == m and nil == w)
                   'ユーザについて'
                 else
                 u = if(m.message[:retweet])
                       m.message[:retweet].user
                     else
                       m.message.user end
                 "#{u[:idname]}(#{u[:name]})について".gsub(/_/, '__') end },
               lambda{ |m, w| m.message.repliable? },
               lambda{ |m, w|
                 user = if(m.message[:retweet]) then m.message[:retweet].user else m.message.user end
                 makescreen(user, service) } ]
      [menu] }
  end

  def self.makescreen(user, service)
    if user[:exact]
      @tabclass.new("#{user[:idname]}(#{user[:name]})", service,
                    :user => user,
                    :icon => user[:profile_image_url])
    else
      Thread.new{
        retr = service.scan(:user_show, :screen_name => user[:idname],
                             :no_auto_since_id => true)
        Delayer.new{ makescreen(retr.first, service) } if retr }
    end end

  boot
end
