#!/usr/bin/python
# -*- coding: utf-8 -*-
"""blosxom-client v0.05 : A simple blosxom client."""
import pygtk
pygtk.require("2.0")
import gtk
import pango
import ftplib
import time
import os
import re

class BlosxomClient:
	def __init__(self):
		"""
		初期化処理
		"""
		self.settings = {}
		self.links = {}
		self.load_settings()

	def is_wysiwyg(self):
		if self.settings.has_key("wysiwyg"):
			return self.settings["wysiwyg"] == "true"
		return False

	def get_html(self):
		"""
		TextViewからのHTML取得処理
		TextTagからHTMLタグに変換
		"""
		iter = self.buffer.get_start_iter()
		if not self.is_wysiwyg():
			end_iter = self.buffer.get_end_iter()
			return self.buffer.get_text(iter, end_iter)
		html = ''
		bold_prev = False
		italic_prev = False
		link_prev = False
		while not iter.is_end():
			bold = iter.has_tag(self.bold_tag)
			italic = iter.has_tag(self.italic_tag)
			link = iter.has_tag(self.link_tag)
			image = iter.has_tag(self.image_tag)
			url = ''
			for tag in iter.get_tags():
				for mark in iter.get_marks():
					url = self.links.get(mark.get_name(), '')

			if link == True and link != link_prev:
				html += "<a href=\"%s\">" % url;
			if bold == True and bold != bold_prev:
				html += "<b>";
			if italic == True and italic != italic_prev:
				html += "<i>";
			if image == True:
				html += "<img src=\"%s\">" % url;
			if italic == False and italic != italic_prev:
				html += "</i>";
			if bold == False and bold != bold_prev:
				html += "</b>";
			if link == False and link != link_prev:
				html += "</a>";
			bold_prev = bold
			italic_prev = italic
			link_prev = link

			iter_orig = iter.copy()
			tag_found = iter.forward_to_tag_toggle(None)
			if not tag_found:
				iter = self.buffer.get_end_iter()
			text = self.buffer.get_text(iter_orig, iter)
			text = text.replace("&", "&amp;")
			text = text.replace("\"", "&quot;")
			text = text.replace("<", "&gt;")
			text = text.replace(">", "&lt;")
			text = text.replace("\n", "<br>\n")
			html += text
		return html

	def insert_link(self, is_image = False):
		"""
		リンク挿入処理
		ダイアログから入力されたリンク（もしくは画像パス）を挿入
		"""
		dialog = gtk.Dialog("追加",
				buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
				"追加(_A)", gtk.RESPONSE_ACCEPT))
        
		dialog.set_default_response(gtk.RESPONSE_ACCEPT)
		dialog.set_has_separator(False)
		dialog.set_resizable(False)
		dialog.vbox.set_spacing(2)

		table = gtk.Table(2, 2)
		dialog.vbox.pack_start(table)

		label = gtk.Label("タイトル:")
		label.set_alignment(0.0, 0.5)
		table.attach(label, 0, 1, 0, 1, gtk.FILL)

		title = gtk.Entry()            
		table.attach(title, 1, 2, 0, 1)

		label = gtk.Label("URL:")
		label.set_alignment(0.0, 0.5)
		table.attach(label, 0, 1, 1, 2, gtk.FILL)

		url = gtk.Entry()
		url.set_activates_default(True)
		table.attach(url, 1, 2, 1, 2)

		selection = self.buffer.get_selection_bounds()
		if selection:
			title.set_text(self.buffer.get_text(selection[0], selection[1]))

		table.show_all()

		if selection:
			url.grab_focus()
		else:
			title.grab_focus()

		response = dialog.run()

		link_title = None
		link_url = None
		if response == gtk.RESPONSE_ACCEPT:
			link_title = title.get_text()
			link_url = url.get_text()
			ins_mark = self.buffer.get_insert()
			if not is_image:
				tag = self.link_tag
			else:
				tag = self.image_tag
			mark_iter = self.buffer.get_iter_at_mark(ins_mark)
			if self.is_wysiwyg():
				if not selection:
					self.buffer.insert_with_tags(mark_iter, link_title, tag)
				else:
					self.buffer.apply_tag(tag, selection[0], selection[1])
			else:
				if is_image:
					link_title = "<img src=\"%s\" title=\"%s\">" % (link_url, link_title)
				else:
					link_title = "<a href=\"%s\" target=\"_blank\">" % link_url
				if not selection:
					self.buffer.insert(mark_iter, link_title)
				else:
					self.buffer.insert(selection[0], link_title)
					self.buffer.insert(selection[1], tag.closing_tag)
			mark = self.buffer.create_mark("%03d" % len(self.links), mark_iter)
			self.links[mark.get_name()] = link_url

		dialog.hide()

	def on_menu_bold(self, widget):
		"""
		メニュー「太字」のハンドラ
		太字タグを適応する
		"""
		selection = self.buffer.get_selection_bounds()
		if not selection:
			return
		if self.is_wysiwyg():
			if selection[0].has_tag(self.bold_tag):
				self.buffer.remove_tag(self.bold_tag, selection[0], selection[1])
			else:
				self.buffer.apply_tag(self.bold_tag, selection[0], selection[1])
		else:
			text = self.bold_tag.opening_tag + self.buffer.get_text(selection[0], selection[1]) + self.bold_tag.closing_tag
			self.buffer.delete(selection[0], selection[1])
			self.buffer.insert_at_cursor(text)

	def on_menu_italic(self, widget):
		"""
		メニュー「斜体」のハンドラ
		斜体タグを適応する
		"""
		selection = self.buffer.get_selection_bounds()
		if not selection:
			return
		if self.is_wysiwyg():
			if selection[0].has_tag(self.italic_tag):
				self.buffer.remove_tag(self.italic_tag, selection[0], selection[1])
			else:
				self.buffer.apply_tag(self.italic_tag, selection[0], selection[1])
		else:
			text = self.italic_tag.opening_tag + self.buffer.get_text(selection[0], selection[1]) + self.italic_tag.closing_tag
			self.buffer.delete(selection[0], selection[1])
			self.buffer.insert_at_cursor(text)

	def on_menu_link(self, widget):
		"""
		メニュー「リンク」のハンドラ
		リンク挿入処理を呼び出す
		"""
		self.insert_link(False)

	def on_menu_image(self, widget):
		"""
		メニュー「画像」のハンドラ
		リンク挿入処理（画像）を呼び出す
		"""
		self.insert_link(True)

	def on_menu_help(self, widget):
		"""
		メニュー「ヘルプ」のハンドラ
		ヘルプダイアログを表示する
		"""
		dialog = gtk.MessageDialog(self.window,
				gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO,
				gtk.BUTTONS_CLOSE,
				"blosxom-client v0.05 : A simple blosxom client.\n\tby mattn")
		dialog.run()
		dialog.destroy()

	def on_button_clicked(self, button):
		"""
		ボタン「公開」のハンドラ
		FTPにアクセスしてフォルダを生成し、記事をポストする
		"""
		buffer = self.body.get_buffer()
		start_iter = buffer.get_start_iter()
		end_iter = buffer.get_end_iter()
		txt = buffer.get_text(start_iter, end_iter, 0)
		filename = "%i.%s" % (int(time.time()), "txt")
		message = "サーバに接続中..."
		try:
			ftp = ftplib.FTP(self.settings["server"])
			message = "サーバにログイン中..."
			ftp.login(self.settings["userid"], self.settings["password"])
			message = "公開ディレクトリに移動中..."
			ftp.cwd(self.settings["publish_root"])
			categories = self.category.get_text().split("/")
			for c in categories:
				if not c:
					continue
				try:
					ftp.cwd(c)
				except:
					message = "公開ディレクトリにディレクトリを作成中..."
					ftp.mkd(c);
					ftp.cwd(c)
			message = "ローカルにテンポラリを作成中..."
			file = open(filename, "w")
			file.write(self.title.get_text())
			file.write("\n")
			file.write(txt)
			file.close()
			message = "ローカルのテンポラリを読み込み中..."
			file = open(filename, "rb")
			message = "エントリファイルのアップロード中..."
			ftp.storbinary("STOR %s" % filename, file)
			ftp.quit()
			file.close()
			message = "ローカルのテンポラリを削除中..."
			os.remove(filename)
		except Exception, e:
			try:
				ftp.close()
			except:
				pass
			try:
				file.close()
			except:
				pass
			try:
				os.remove(filename)
			except:
				pass
			dialog = gtk.MessageDialog(self.window,
					gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR,
					gtk.BUTTONS_CLOSE,
					message + "\n" + str(e))
			dialog.run()
			dialog.destroy()

	def load_settings(self):
		"""
		設定ファイルを読み込む
		"""
		fname = os.path.expanduser("~/.blosxom-client")
		try:
			file = open(fname, "r")
			reg = re.compile("^([^=]+)=(\S*)$")
			while 1:
				line = file.readline()
				if not line:
					break
				m = reg.search(line)
				self.settings[m.group(1)] = m.group(2)
			file.close
		except:
			pass

	def main(self):
		"""
		メイン処理
		"""
		self.window = gtk.Window()
		self.window.set_title("Blosxom Client")
		self.window.connect("delete-event", gtk.main_quit)

		accel_group = gtk.AccelGroup()
		self.window.add_accel_group(accel_group)

		vbox = gtk.VBox()
		vbox.set_spacing(2)
		self.window.add(vbox)

		menubar = gtk.MenuBar()
		vbox.pack_start(menubar, expand=False)

		# ファイルメニュー
		menuitem = gtk.MenuItem('ファイル(_F)')

		menu = gtk.Menu()
		submenuitem = gtk.MenuItem('終了(_X)')
		submenuitem.connect("activate", gtk.main_quit, "file.quit")
		submenuitem.add_accelerator('activate', accel_group, gtk.gdk.keyval_from_name("q"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
		menu.add(submenuitem)
		menuitem.set_submenu(menu)

		menubar.add(menuitem)

		# 編集メニュー
		menuitem = gtk.MenuItem('編集(_E)')

		menu = gtk.Menu()
		submenuitem = gtk.MenuItem('太字(_B)')
		submenuitem.connect("activate", self.on_menu_bold)
		submenuitem.add_accelerator('activate', accel_group, gtk.gdk.keyval_from_name("b"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
		menu.add(submenuitem)
		submenuitem = gtk.MenuItem('斜体(_I)')
		submenuitem.connect("activate", self.on_menu_italic)
		submenuitem.add_accelerator('activate', accel_group, gtk.gdk.keyval_from_name("i"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
		menu.add(submenuitem)
		menuitem.set_submenu(menu)
		submenuitem = gtk.MenuItem('リンク(_L)')
		submenuitem.connect("activate", self.on_menu_link)
		submenuitem.add_accelerator('activate', accel_group, gtk.gdk.keyval_from_name("r"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
		menu.add(submenuitem)
		menuitem.set_submenu(menu)
		submenuitem = gtk.MenuItem('画像(_L)')
		submenuitem.connect("activate", self.on_menu_image)
		submenuitem.add_accelerator('activate', accel_group, gtk.gdk.keyval_from_name("t"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
		menu.add(submenuitem)
		menuitem.set_submenu(menu)

		menubar.add(menuitem)

		# ヘルプメニュー
		menuitem = gtk.MenuItem('ヘルプ(_H)')
		menuitem.set_right_justified(True)

		menu = gtk.Menu()
		submenuitem = gtk.MenuItem('blosxom-clientについて(_A)')
		submenuitem.connect("activate", self.on_menu_help)
		menu.add(submenuitem)
		menuitem.set_submenu(menu)

		menubar.add(menuitem)

		table = gtk.Table(2, 3, False)
		table.set_border_width(10)
		table.show()
		vbox.add(table)

		label = gtk.Label("タイトル: ")
		table.attach(label,
				0, 1,                   0, 1,
				gtk.FILL,  gtk.EXPAND | gtk.FILL,
				0,                      0)
		self.title = gtk.Entry()
		table.attach(self.title,
				1, 2,                   0, 1,
				gtk.EXPAND | gtk.FILL,  gtk.EXPAND | gtk.FILL,
				0,                      0)

		label = gtk.Label("カテゴリ: ")
		table.attach(label,
				0, 1,                   1, 2,
				gtk.FILL,  gtk.EXPAND | gtk.FILL,
				0,                      0)
		self.category = gtk.Entry()
		table.attach(self.category,
				1, 2,                   1, 2,
				gtk.EXPAND | gtk.FILL,  gtk.EXPAND | gtk.FILL,
				0,                      0)

		sw = gtk.ScrolledWindow()
		sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		table.attach(sw,
				0, 2,                   2, 3,
				gtk.EXPAND | gtk.FILL,  gtk.EXPAND | gtk.FILL,
				0,                      0)

		self.body = gtk.TextView()
		self.body.set_size_request(500, 200)
		self.body.queue_resize()
		font = pango.FontDescription('Sans 12')
		self.body.modify_font(font)
		sw.add(self.body)

		self.buffer = self.body.get_buffer()
		self.bold_tag = self.buffer.create_tag("b")
		self.bold_tag.opening_tag = '<b>'
		self.bold_tag.closing_tag = '</b>'
		self.bold_tag.set_property("weight", pango.WEIGHT_BOLD)
		self.italic_tag = self.buffer.create_tag("i")
		self.italic_tag.opening_tag = '<i>'
		self.italic_tag.closing_tag = '</i>'
		self.italic_tag.set_property("style", pango.STYLE_ITALIC)
		self.link_tag = self.buffer.create_tag("a")
		self.link_tag.opening_tag = '<a>'
		self.link_tag.closing_tag = '</a>'
		self.link_tag.set_property("underline", pango.UNDERLINE_SINGLE)
		self.link_tag.set_property("foreground", "#0000FF")
		self.image_tag = self.buffer.create_tag("img")
		self.image_tag.opening_tag = '<img>'
		self.image_tag.closing_tag = None

		button = gtk.Button("公開")
		button.connect("clicked", self.on_button_clicked)
		vbox.add(button)

		self.window.show_all()
		gtk.main()

if __name__=='__main__':
	try:
		blosxom_client = BlosxomClient()
		blosxom_client.main()
	except Exception, e:
		print(e)
		pass
