namespace eval tastebin {
	package require http
	package require msgcat
	
	variable script_dir [file dirname [info script]]
	::msgcat::mcload [file join $script_dir msgs]
	
	variable options
	custom::defgroup Plugins \
	[::msgcat::mc "Plugins options."] \
	-group Tkabber	
    custom::defgroup Tastebin \
	[::msgcat::mc "Tastebin options"] \
	-group Plugins	
	custom::defvar options(save_history_to_file) 1 \
	[::msgcat::mc "Save history to file"] \
	-group Tastebin -type boolean
	custom::defvar options(nick) {} \
	[::msgcat::mc "Automatically insert your nickname in every post"] \
	-group Tastebin -type string
	custom::defvar options(auto_save_to_favotites) 0 \
	[::msgcat::mc "Automatically save all posted highlights to favorites list"] \
	-group Tastebin -type boolean
	custom::defvar options(history_maximum_lines) 15 \
	[::msgcat::mc "Maximum lines of post for saving to history"] \
	-group Tastebin -type integer
	
	custom::defvar options(autopost,enabled) 1 \
	[::msgcat::mc "Automatically send a message to the server, if it are exceeding limit"] \
	-group Tastebin -type boolean
	custom::defvar options(autopost,maximum_chars) 800 \
	[::msgcat::mc "Limit the number of characters, after which will automatically send to the server"] \
	-group Tastebin -type integer	
	custom::defvar options(autopost,open_window) 1 \
	[::msgcat::mc "Open a window tastebin if exceeded the size of messages"] \
	-group Tastebin -type boolean	
	
	variable last_lang
	custom::defvar last_lang {} {} \
	-group Hidden -type boolean	
	
	variable highlights
	custom::defvar highlights(fav_names) {} {} \
	-group Hidden -type boolean	
	
	variable NS [namespace current]
	hook::add finload_hook ${NS}::handle
	hook::add chat_send_message_hook ${NS}::handle_command	
	hook::add generate_completions_hook ${NS}::command_comps
	hook::add chat_win_popup_menu_hook ${NS}::popup_menu 1
}


proc tastebin::handle { } {
	variable highlights
	
	lassign [get_highlights] highlights(names) highlights(codes)
	create_buttons
}


# Варианты открытия диалога tastebin
# Toolbar-button
# Menu Services / Plugins / command
# + {} - {}

proc tastebin::create_buttons { } {
	variable script_dir
	variable NS
	
    set pasteimg toolbar.png

    if {[catch {package require Img}]} {
        set pasteimg toolbar.gif
    }

	image create photo \
		plugins/tastebin-button -file \
		[file join $script_dir pixmaps $pasteimg]
	
	ifacetk::add_toolbar_button \
		plugins/tastebin-button \
		${NS}::open_dialog \
		[::msgcat::mc "Tastebin"] 
	
	[.mainframe getmenu services] insert \
		[::msgcat::mc "Plugins"] \
		separator
		
	[.mainframe getmenu services] insert \
		[::msgcat::mc "Plugins"] command \
		-label [::msgcat::mc "Tastebin"] \
		-command ${NS}::open_dialog
}


# Чтение содержимого файла "highlights"
# и инициализация кодов и названий
# поддерживаемых подсветок синтаксиса.
# + {} - {{названия подсветок} {коды подсветок}}

proc tastebin::get_highlights { } {
	variable script_dir
	
	set chan [open [file join $script_dir highlights] RDONLY]
	while {![eof $chan]} {
		lassign [gets $chan] name code
		lappend hlnames $name
		lappend hlcodes $code
	}
	close $chan
	return [list $hlnames $hlcodes]
}
	
#################################################
# Диалог tastebin.

proc tastebin::open_dialog { {start_str {}} {start_lang {}} } {
	variable NS
	variable options
	variable highlights
	variable last_lang
	variable save_fav
	
	set w [unicue_win_path]
	set save_fav 0
	
	add_win $w -title [::msgcat::mc "Tastebin - pastebin uploader"] \
		-tabtitle [::msgcat::mc "Tastebin"] \
	    -raisecmd [list focus $w]
		
	frame $w.main -relief ridge -pady 3
	
	label $w.main.help_lang -text [::msgcat::mc "Syntax Highlighting"]
	set L [entry $w.main.lang -state disabled]
	pack $w.main.help_lang -anchor w 
	pack $w.main.lang -fill x -pady 2
		
	label $w.main.help_nick -text [::msgcat::mc "Paste name"]
	set H [entry $w.main.header]
	pack $w.main.help_nick -anchor w 
	pack $w.main.header -fill x -pady 2
		
	set T [text $w.main.txt -yscrollcommand [list $w.main.ys set] \
		-maxundo 0 -undo true -wrap word]
	scrollbar $w.main.ys -command [list $w.main.txt yview]
	pack $w.main.txt -pady 2 -side left -fill both -expand 1
        pack $w.main.ys -pady 2 -side left -fill y -anchor ne
	
	frame $w.options_bar -bd 2 -pady 2
		
	button $w.options_bar.send \
		-text [msgcat::mc "Send"] \
		-command [list ${NS}::send $L $H $T]
		
	button $w.options_bar.clean \
		-text [msgcat::mc "Clean"] \
		-command [list ${NS}::del_content $T]
		
	button $w.options_bar.history \
		-text [msgcat::mc "History"] \
		-command [list ${NS}::history $T]
	
	button $w.options_bar.close \
		-text [msgcat::mc "Close"] \
		-command [list ${NS}::close $w]
	
	pack $w.options_bar.send $w.options_bar.clean \
	$w.options_bar.history $w.options_bar.close -side left -fill x -padx 4 -expand 1
	
	frame $w.fav_lang -bd 2 -pady 2
	label $w.fav_lang.lab -text [msgcat::mc "Favorite highlights"]
	listbox $w.fav_lang.list -listvariable ${NS}::highlights(fav_names) \
	-yscrollcommand [list $w.fav_lang.ys set] -height 7
	scrollbar $w.fav_lang.ys -command [list $w.fav_lang.list yview]	
	pack $w.fav_lang.lab -anchor w
		
	frame $w.lang -bd 2 -pady 3
	label $w.lang.lab -text [msgcat::mc "All highlights"]
	listbox $w.lang.list -listvariable ${NS}::highlights(names) \
	-yscrollcommand [list $w.lang.ys set] -height 1000
	scrollbar $w.lang.ys -command [list $w.lang.list yview]	
	pack $w.lang.lab -anchor w
	
        pack $w.fav_lang.ys -fill y -pady 2 -side right
	pack $w.fav_lang.list -fill both -pady 2 -anchor ne
        
        pack $w.lang.ys -fill y -pady 2 -side right
        pack $w.lang.list -fill both -pady 2 -anchor se

        pack $w.options_bar -pady 2 -anchor ne -side bottom -fill x
        pack $w.main -padx 2 -pady 2 -expand 1 -anchor se -side left -fill both
        pack $w.fav_lang -padx 2 -anchor ne -side top
        pack $w.lang -padx 2 -anchor se -side top

	$L configure -state normal
	$L insert 0 $start_lang
	
	if {[string equal $start_lang {}]} {
	$L insert 0 $last_lang
	}
	
	$L configure -state disabled
	
	$T insert 0.0 $start_str
	$H insert 0 $options(nick)
	
	bind  $w.lang.list <<ListboxSelect>> [list ${NS}::lang_selected %W $L]
	bind  $w.fav_lang.list <<ListboxSelect>> [list ${NS}::lang_selected %W $L]
	bind $w.main.txt <3> [list ${NS}::create_menu %W %X %Y]
	bind $w.lang.list <3> [list ${NS}::update_favorite_list add %W %X %Y]
	bind $w.fav_lang.list <3> [list ${NS}::update_favorite_list del %W %X %Y]
	
	eval [ format { proc $w { who {text {}} } {
			set T %s
			switch -- $who {
				put {
					$T insert end $text
				}
				clean {
					del_content $T
				}
			}
		}
	 } $T ]
	
	return $w
}

proc tastebin::update_favorite_list { type w x y } {

	set idx [$w curselection]
	
	if {[string length $idx] < 1} {
		return
	}
	
	set lang_name [$w get $idx]
	
	if [winfo exist $w.choise_menu] {
		destroy $w.choise_menu
	}
	
	menu $w.choise_menu -tearoff 0

	switch -- $type {
		add {
			$w.choise_menu add command -label [::msgcat::mc "Add to favorite list"] \
				-command  [list [namespace current]::fav_lang_add $lang_name]
		}
		del {
			$w.choise_menu add command -label [::msgcat::mc "Remove from favorite list"] \
				-command  [list [namespace current]::fav_lang_del $lang_name]
		}
	}
		
	tk_popup $w.choise_menu $x $y
}

# Инициирующая команда для клика
# по элементу Listbox.
# + {путь_к_listbox путь_окна_индикации} - {}

proc tastebin::lang_selected { w L } {
	set idx [$w curselection]
	if {[string length $idx] < 1} return
	set lang_name [$w get $idx]
	insert_lang $L $lang_name
	variable last_lang $lang_name
}

# Вставляет указанный язык в окно
# индикации выбранного языка.
# + {путь_окна_индикации имя_языка} - {}

proc tastebin::insert_lang { L lang_name } {
	$L configure -state normal
	$L delete 0 end
	$L insert 0 $lang_name
	$L configure -state readonly
}

# Инициализирует всплывающее меню 
# для правой кнопки мыши
# + {путь_содержимого_поста X Y} - {}

proc tastebin::create_menu { T x y } {
	variable NS
	
	set m $T.popup
	
	if {[winfo exists $m]} {
		destroy $m
    }
	
	menu $m -tearoff 0
	
	$m add command -label [::msgcat::mc "Cut"] -command  [list ${NS}::cut $T]
	$m add command -label [::msgcat::mc "Copy"] -command  [list ${NS}::copy $T]
	$m add command -label [::msgcat::mc "Paste"] -command  [list ${NS}::paste $T]
	$m add command -label [::msgcat::mc "Undo"] -command  [list ${NS}::undo $T]
	$m add command -label [::msgcat::mc "Redo"] -command  [list ${NS}::redo $T]
	$m add command -label [::msgcat::mc "Select all"] -command  [list ${NS}::select_all $T]
	
	tk_popup $m $x $y
}
#################################################
# Добавить / удалить избранные языки

proc tastebin::fav_lang_add { lang } {
	variable highlights
	if ![fav_lang_exist $lang] {
		lappend highlights(fav_names) $lang
	}
}

proc tastebin::fav_lang_exist { lang } {
	variable highlights
	if {[lsearch -exact highlights(fav_names) $lang] >= 0} {
		return 1
	}
	return 0
}

proc tastebin::fav_lang_del { lang } {
	variable highlights
	if {[set ix [lsearch -exact $highlights(fav_names) $lang]] >= 0} {
		set highlights(fav_names) [lreplace $highlights(fav_names) $ix $ix]
	}
}

#################################################
# Команды для всплывающего меню
# cut, copy, paste, undo, redo, select_all
# + {путь_содержимого_поста} - {}

proc tastebin::cut { T } {
	if {![catch {set data [$T get sel.first sel.last]}]} {
		clipboard clear -displayof $T
		clipboard append -displayof $T $data
		$T delete sel.first sel.last
	}
}

proc tastebin::copy { T } {
	if {![catch {set data [$T get sel.first sel.last]}]} {
		clipboard clear -displayof $T
		clipboard append -displayof $T $data
	}
}

proc tastebin::undo { T } {
	catch {$T edit undo}
}

proc tastebin::redo { T } {
	catch {$T edit redo}
}

proc tastebin::select_all { T } {
	$T tag add sel 1.0 end
}

proc tastebin::paste { T } {
	global tcl_platform
	if {![catch {::tk::GetSelection $T CLIPBOARD} sel]} {
		set oldSeparator [$T cget -autoseparators]
		if {$oldSeparator} {
			$T configure -autoseparators 0
			$T edit separator
		}
		if {[tk windowingsystem] ne "x11"} {
			catch { $T delete sel.first sel.last }
		}
		$T insert insert $sel
		if {$oldSeparator} {
			$T edit separator
			$T configure -autoseparators 1
		}
	}
}

#################################################
# Команды для send, del_content, history и close.

# Отправка поста на сервер pastebin.com
# + {
# путь_индикатора_подсветки(entry)
# путь_имени_пользователя(entry)
# путь_содержимого поста(text)
# } - {}

proc tastebin::send { L H T } {
	variable NS
	variable options
	
	set URL "http://pastebin.com/api/api_post.php"
	set HISTORY [$T get 0.0 $options(history_maximum_lines).0]
	set CODE [$T get 0.0 end]
	set NAME [$H get]
	set LANG_NAME [$L get]
	
	if {[string length $CODE] <= 1} {
		return [info_message [::msgcat::mc "Empty string."] \
		[::msgcat::mc "Error!"] warning]
	}
	
	if {[string length $NAME] == 0} {
	set NAME "Tastebin - Tkabber Plugin"
	}
	
	if {[string length $LANG_NAME] == 0} {
	set LANG "text"
	} else {
	set LANG [get_lang_code $LANG_NAME]
	}
	
	$T delete 0.0 end
	$T insert 0.0 [::msgcat::mc "Please wait ..."]
	$T configure -state disabled
	
	set post [http::formatQuery api_dev_key "d037ba11d265d3a7232d3eb5d6d1fa64" \
        api_option "paste" api_paste_code $CODE api_paste_format $LANG \
        api_paste_name $NAME api_paste_private "1"]
	
	set token [http::geturl $URL -query $post]
	http::wait $token
	
	set status [http::status $token]
	set data [http::data $token]
	http::cleanup $token
	
	if ![string equal $status ok] {
		$T configure -state normal
		$T delete 0.0 end
		$T insert 0.0 "Error"
		return
	}
	
	add_history "[get_time]\t$LANG - \
	${data}:\n\n$HISTORY\
	\n...\n[string repeat _ 20]\n\n"
		
	if $options(auto_save_to_favotites) {
		fav_lang_add $LANG_NAME
	}
	
	$T configure -state normal
	$T delete 0.0 end
	$T insert 0.0 $data
}

# Всплывающее окно нотификации
# + {сообщение ?заголовок? ?тип?} - {}

proc tastebin::info_message { msg {title Info} {type info} } {
	tk_messageBox -default ok \
		-message $msg -title $title \
		-icon $type -type ok
}

# Вернуть код подсветки по названию
# + {имя_подсветки} - {код_подсветки}

proc tastebin::get_lang_code { LANG } {
	variable highlights
	if {[set ix [lsearch -exact $highlights(names) $LANG]] >= 0} {
		return [lindex  $highlights(codes) $ix]
	} 
	return text
}

# Возвращает время в принятом в Tkabber 
# формате.
# + {} - time

proc tastebin::get_time { } {
	return [clock format [clock seconds] \
	-format $::plugins::options(delayed_timestamp_format)]
}

# Удаляет содержимое поста
# + {путь_содержимого_поста} - {}
proc tastebin::del_content { T } {
	$T configure -state normal
	$T delete 0.0 end
}

# Закрывает окно поста
# + {путь_окна_поста} - {} 
proc tastebin::close { w } {
	destroy_win $w
}

# Показывает историю постов 
# в поле редактирования поста.
# + {путь_окна_поста} - {}
proc tastebin::history { T } {
	$T configure -state normal
	$T delete 0.0 end
	$T insert 0.0 [get_history]
}

#################################################
# History команды

proc tastebin::add_history { msg } {
	variable options
	
	lappend options(history) $msg
	
	if {!$options(save_history_to_file)} {
	return
	}
	
	catch { file mkdir [file join $::configdir tastebin_history]}
	set file [open [file join $::configdir tastebin_history history] a]
	
	puts $file $msg
	flush $file
	close $file
}

proc tastebin::get_history { } {
	variable options
	variable script_dir
	
	if !$options(save_history_to_file) {
		if [info exist options(history)] {
			return $options(history)
		}
		return 
	}
	
	if {![file exist [file join $::configdir tastebin_history history]]} {
		return
	}

	set file [open [file join $::configdir tastebin_history history] r]
	
	set data [read $file]
	close $file
	return $data
}

#################################################

# Создаёт уникальный путь размещения
# виджета toplevel.
# Создана для поддержки открытия нескольких диалогов
# + {} - {path}

proc tastebin::unicue_win_path { } {
	variable unique_id
	return .tastebin_[incr unique_id]
}

#################################################
# Автоматический пост сообщений 
# при превышении ограничения

proc tastebin::command_comps {chatid compsvar wordstart line} {
    upvar 0 $compsvar comps
    if {!$wordstart} { lappend comps {/paste } {/-paste} {/paste langs}}
}

proc tastebin::handle_command {chatid user body type} {
	variable options
	variable highlights
	
	if {[string match {/paste langs*} $body]} {
		show info  $chatid [join $highlights(names) "     |     "]
		return -code break
	}
	
	if {[string match {/paste*} $body]} {
		if {[string length $body] < 10} {
			show error $chatid [::msgcat::mc "Too many chars"]
			return -code break
		} else {
		
			set lang text
			foreach name $highlights(names) {
				set len [string length $name]
				set tname [string tolower $name]
				set tbody [string range [string tolower $body] 7 end]
				if [string equal -length $len $tname $tbody] {
					show info $chatid  ">>> $name"
					set lang [get_lang_code $name]
					set body [string range $body $len end]
				}
			}
			
			set out [post_message [string range $body 7 end] $lang]
			show info $chatid " >>> $out"
			add_history "[get_time]\t${out}[string repeat _ 20]\n\n"
			return -code break
		}
	}
	
	if {[string match {/-paste*} $body]} {
		return 
	}
	
	if {$options(autopost,enabled)} {
		if {[string length $body] >= $options(autopost,maximum_chars)} {
			if {$options(autopost,open_window)} {
				open_dialog $body
				return -code break
			}
			set link [post_message $body]
			show info $chatid [::msgcat::mc "Your message are exceeding limit"]
			show info $chatid " >>> $link"
			### WARNING ZONE!!!!! ###
			after 50 [list [chat::input_win $chatid] insert end $link]
			return -code break
		}
	}
}
	
proc tastebin::post_message { body {lang text}} {
	set url "http://pastebin.com/api_public.php"
	set name "Tastebin - Tkabber Plugin"
	set post [http::formatQuery paste_code $body \
		paste_format $lang paste_name $name]
	set token [http::geturl $url -query $post]
	set data [http::data $token]
	http::cleanup $token
	return $data
}

proc tastebin::show {type chatid msg} {
	set jid [chat::get_jid $chatid]
	set cw [chat::chat_win $chatid]
	chat::add_message $chatid $jid $type $msg {}
}

proc tastebin::popup_menu { m chatwin X Y x y } {
	variable options
	variable NS
	
	set tags [$chatwin tag names "@$x,$y"]	
    set idx [lsearch $tags href_*]
	set idx1 [lsearch $tags uri*]
	
	 if { $idx < 0 } {
		return
	}
	
    if { $idx1 >= 0 } {
		set url [lindex [lindex $tags $idx1] 1]
    } else {
		lassign [$w tag prevrange url "@$x,$y"] a b
		set url [$w get $a $b]
    }
	
	if {[regexp -- {http://pastebin.com/(.*)} $url => part]} {
		set url "http://pastebin.com/raw.php?i=$part"

		$m add command \
			-label [::msgcat::mc "Show pastebin content"] \
			-command [list ${NS}::get_pastebin_url $url]
		$m add separator
	}
}

proc tastebin::get_pastebin_url { url } {
	variable NS
	
	set w [open_dialog [::msgcat::mc "Please wait ..."]]

	if {[catch {set token [http::geturl $url]}]} {
		$w clean
		$w put [::msgcat::mc "Error"]
		return
	}
	
	http::wait $token
	
	set status [http::status $token]
	
	if {![string equal $status ok]} {
		$w clean
		$w put [::msgcat::mc "Error"]
		return
	}
	
	set data [http::data $token]
	http::cleanup $token 
	
	$w clean
	$w put $data
}