/*
    Copyright 2010 by BoscoWitch

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


using GLib;
using Notify;
using Gtk;
using Sqlite;
using Posix;

public class WadokuNotify : GLib.Object {

    public static const string version = "0.2";
    

    public static string Path;
    public static int rc;
    public static Database db;
    public static Sqlite.Callback CallbackFunc;
    
//Settings
    public enum OutputType { stdout,Gtk,LibNotify }
    public static int output;
    public static int reading;
    public static bool japanese_only;
    public static int time;
    public static int res_nr;
    public static string result_nr;

//clipboard stuff
    public static Clipboard clip;
    public static string text;
    public static string old_text;


//gui outputs
    public static Notification not;
    public static Gtk.Window window;
    public static Gtk.Label label;
    public static uint Timer;
    
    public static void clipboard_changed() {
    	text = clip.wait_for_text();
    	
    	if(text != null && text != old_text && text.length >= 1) {
		text = text.replace("\"","`");
    		//first char is Kanji or Katakana
    		if( (text.get_char() >=  0x4E00 && text.get_char() <= 0x9FAF) ||  (text.get_char() >=  0x30A0  && text.get_char() <= 0x30FF)) {
    			rc = db.exec ("""select japanese,reading,german,romanjireading from entries where
    						japanese like """"+ text +"""" or
    						japanese like """"+ text +""" %" or
    						japanese like """"+ text +"""%" or
    						japanese like "%"""+ text +"""%" 
    						order by LENGTH(japanese_stripped) asc limit """+ res_nr.to_string() +""",1;""", CallbackFunc, null);
    		} 
    		//first char is Hiragana
    		else if(text.get_char() >= 0x3040 && text.get_char() <= 0x309F) {
    			rc = db.exec ("""select japanese,reading,german,romanjireading from entries where
    						reading like """"+ text + """" or  
    						reading like """"+ text + """%" or 
    						reading like "%"""+ text + """%" order by LENGTH(reading_stripped) asc limit """+ res_nr.to_string() +""",1;""" , CallbackFunc, null);
    		}
    		else if(!japanese_only){
    			rc = db.exec ("""select japanese,reading,german,romanjireading from entries where
    						japanese like """"+ text +"""" or
    						reading like """"+ text + """" or
    						japanese like """"+ text +"""%" or
    						japanese like "%"""+ text +"""%" or  
    						reading like """"+ text + """%" or 
    						reading like "%"""+ text + """%" or 
    						german like "%"""+ text +"""%" order by LENGTH(reading_stripped) asc limit """+ res_nr.to_string() +""",1;""", CallbackFunc, null);
    		}
    		
    		if (rc != Sqlite.OK) {
         		GLib.stderr.printf ("SQL error: %d, %s\n", rc, db.errmsg ());
        	}
    	}
    }


    
    
    public static int callback_notify (int n_columns, string[] values,
                                string[] column_names)
    {
        if(text == old_text) return 0;
        old_text = text;
        string temp = "%s\n%s".printf(values[reading],values[2]);
        
        //cut if too long for libnotify
        if(output == OutputType.LibNotify && temp.length > 300)
        	temp = temp.substring(0,300) + "...";
        
        if(not!=null)
        	not.update(values[0], temp, "%s/wadoku.png".printf(Path));
        else
		not = new Notification(values[0], temp, "%s/wadoku.png".printf(Path), null);
	not.set_timeout(time);
	not.set_urgency(Notify.Urgency.CRITICAL);
	not.show();
		
        return 0;
    }




    public static int callback_ownerdrawn (int n_columns, string[] values,
                                string[] column_names)
    {
	if(text == old_text) return 0;
        old_text = text;
        string temp = values[2].replace("<","&#60;");
	temp = temp.replace(">","&#62;");
	temp = temp.replace("&","&amp");
	
	label.set_markup("<span font=\"Meiryo 14\">%s</span>\n%s\n%s".printf(values[0],values[reading],temp));
	window.resize(1,1);
	window.show_all();
	Source.remove(Timer);
	Timer = Timeout.add(time,HideTimer);
        return 0;
    }

    public static bool HideTimer() {
	window.hide_all();
	return false;
    }

    public static void EnterWindow() {
	window.hide_all();
	Source.remove(Timer);
    }


    public static void Next() {
    	res_nr++;
    }
	


    public static int callback_stdout (int n_columns, string[] values,
                                string[] column_names)
    {
	if(text == old_text) return 0;
        old_text = text;

	GLib.stdout.printf("\n %s\n %s\n%s\n",values[0],values[reading],values[2]);

	GLib.stdout.flush();	
        return 0;
    }

    public static int main(string[] args) {
    	res_nr = 0;
	
	output = OutputType.LibNotify;
	reading = 1;
	japanese_only = false;
	time = 5000;

			for(int i=1; i < args.length; i++) {
				if(args[i] == "-v" || args[i] == "--version") {
					GLib.stdout.printf("%s\n",version);
					return 0;
				}
				else if ( args[i] == "-romanji" ) {
					reading = 3;
					continue;
				}		
				else if (args[i] == "-gtk" ) {
					output = OutputType.Gtk;
					continue;
				}
				else if (args[i] == "-stdout") {
					output = OutputType.stdout;
					continue;
				}
				else if (args[i] == "-jap-only") {
					japanese_only = true;
					continue;
				}
				else if (args[i] == "-time") {
					i++;
					if(args[i] == null) {
						GLib.stderr.printf("Please give a timespan in milli seconds to show the notify box\n");
						return -1;
					}
					time = args[i].to_int();
					continue;
				}
				else {
					GLib.stderr.printf("Usage:\n\t-time TIMEINMS sets to time how long to show the notify bos in milli seconds default is 5000\n\t-jap-only only search if japanese characters are selected\n\t-romanji for reading on roman letters instead of japanese hiragana.\n\t-gtk for gtk dialog output or\n\t-stdout for shell standart out stream.\n\tdefault is LibNotify System Notification output\n");
					return -1;
				}
			}
		
    	int rc;

	string exelink;
	char exepath[1024];
	exelink = "/proc/%d/exe".printf(Posix.getpid());

	Posix.readlink(exelink,exepath);
	Path = (string)exepath;

	Path = Path.slice(0,Path.pointer_to_offset(Path.rchr(-1,'/')));
        
        int fd = Posix.open("%s/wadoku_Database_notify-mod2.sqlite3".printf(Path), Posix.O_RDONLY);
	
	if(Posix.posix_fadvise(fd,0,0,Posix.POSIX_FADV_RANDOM|Posix.POSIX_FADV_WILLNEED) == -1)
		GLib.stderr.printf("Could not preload Database file %s","%s/wadoku_Database_notify-mod2.sqlite3".printf(Path));
    	
        if (!FileUtils.test ("%s/wadoku_Database_notify-mod2.sqlite3".printf(Path), FileTest.IS_REGULAR)) {
        	GLib.stderr.printf ("Database %s does not exist or is a directory\n", args[1]);
        	Posix.close(fd);
        	return -1;
        }

 
        rc = Database.open ("%s/wadoku_Database_notify-mod2.sqlite3".printf(Path), out db);
 
        if (rc != Sqlite.OK) {
	    GLib.stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ());
            Posix.close(fd);
            return -1;
        }


    	Gtk.init(ref args);
    	clip = Clipboard.get(Gdk.Atom.intern ("PRIMARY", false));

    	
    	if( output == OutputType.LibNotify ) {
    		Notify.init("wadoku-notify");
		CallbackFunc = callback_notify;
	} 
	else if( output == OutputType.stdout ) {
		CallbackFunc = callback_stdout;
	}
	else { //OutputType.Gtk
		CallbackFunc = callback_ownerdrawn;
		
		window = new Window (WindowType.POPUP);
		window.skip_taskbar_hint = true;
		window.skip_pager_hint = true;
		window.can_focus = false;
		window.move(Gdk.Screen.width() - 310, Gdk.Screen.height() - 250);
		Gdk.Color color;
		Gdk.Color.parse("black", out color);
		window.modify_bg( Gtk.StateType.NORMAL,color);
		window.border_width = 2;
		window.opacity = 0.75f;
		window.set_default_size(300,-1);
		window.destroy.connect (Gtk.main_quit);
		label = new Label("");
		label.selectable = false;
		label.set_line_wrap(true);
		label.set_size_request(300,-1);
		Gdk.Color fg_color;
		Gdk.Color.parse("white",out fg_color);
		label.modify_fg(StateType.NORMAL,fg_color);
		window.add(label);
		Timer = Timeout.add(5000,HideTimer);
		Signal.connect(window,"enter_notify_event", EnterWindow, null);

	}
    	Signal.connect(clip, "owner_change", clipboard_changed , null);
	
    	
        Gtk.main();
	
	Posix.close(fd);
	
        return 0;
    }
    
}

