#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <unistd.h>

//////////////////////////////////////////////////////////////////////////////////////
// GTK program by http://www.garyshood.com
// Requires the gtk library and xvkbd
// This is licensed under the BSD license.
// 
// Copyright (c) 2007, Gary's Hood
// 
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// 
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or 
// other materials provided with the distribution.
// * Neither the name of the Gary's Hood nor the names of its contributors 
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                 
//////////////////////////////////////////////////////////////////////////////////////

void static check_dupe()
{
FILE *fp;
if((fp = fopen(".startlock","r"))!=NULL) {
printf("Dupe detected.\n");
unlink(".lock");
unlink(".startlock");
}
}

void static start_autotype()
{
int fork_return;
int count = 0;
printf("Process %d about to fork a child.\n", getpid() );
fork_return = fork();
if( fork_return < 0)
{
printf("Unable to create child process, exiting.\n");
exit(0);
}
if( fork_return > 0)
{
printf("Created child process %d.\n", fork_return);
while( count++ > -1)
{
char lcount;
FILE *fp;
FILE *fpcheck;
char line[1000];
char autotype[100] = "xvkbd -text \"";
char message[100] = "";
char endautotype[100] = "\\r\"\n";
char sleep[100] = "sleep ";
char delaynum[100] = "";

if((fp = fopen(".lock","r"))==NULL) {
printf("Cannot open file.\n");
exit(1);
}

FILE *fplock = fopen(".startlock","w");
if( fplock ) {
fprintf(fplock, " ");
}
fclose(fplock);

while( fgets(line, sizeof(line), fp) != NULL ) {
lcount++;

if(lcount == 1) {
strcat(delaynum, line);
strcat(sleep, delaynum);
printf(sleep);
if((fpcheck = fopen(".lock","r"))==NULL) {
printf("Cannot open file 63.\n");
exit(1);
}
system(sleep);
}

if(lcount == 2) {
strcat(message, line);
strcat(autotype, message);
strcat(autotype, endautotype);
printf(autotype);
if((fpcheck = fopen(".lock","r"))==NULL) {
printf("Cannot open file 77.\n");
exit(1);
}
system(autotype);
}

}
fclose(fp);
}

}
}

void static delay_callback( GtkWidget *widget, GtkWidget *delay)
{
const gchar *delaynum;

delaynum  = gtk_entry_get_text (GTK_ENTRY (delay));

int num;
sscanf(delaynum,"%d", &num);

if(num > 0 && num < 1000) {
FILE *fp = fopen(".lock","w");
if( fp ) {
fprintf(fp, delaynum);
fprintf(fp, "\n");
}
fclose(fp);
}

}

void static enter_callback( GtkWidget *widget, GtkWidget *entry)
{
const gchar *message;

message = gtk_entry_get_text (GTK_ENTRY (entry));

FILE *fp = fopen(".lock","a");
if( fp ) {
fprintf(fp, message);
fprintf(fp, "\n");
}
fclose(fp);
}


void static stop_autotype()
{
unlink(".lock");
unlink(".startlock");
}

int main( int   argc, char *argv[] )
{
    unlink(".lock");
    unlink(".startlock");
    GtkWidget *window;
    GtkWidget *vbox;
    GtkWidget *entry;
    GtkWidget *delay;
    GtkWidget *button;
    GtkWidget *frame;
    GtkWidget *label;
    GtkAdjustment *adj;
    gint tmp_pos;
    FILE *fp;
    GtkWidget *dialog;

    gtk_init (&argc, &argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request (GTK_WIDGET (window), 400, 240);
    gtk_window_set_title (GTK_WINDOW (window), "Auto Typer");
    g_signal_connect (G_OBJECT (window), "destroy",
                      G_CALLBACK (gtk_main_quit), NULL);
    g_signal_connect_swapped (G_OBJECT (window), "delete_event",
                              G_CALLBACK (gtk_widget_destroy), 
                              G_OBJECT (window));

    vbox = gtk_vbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (window), vbox);
    gtk_widget_show (vbox);
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);

    frame = gtk_frame_new ("Instructions");
    label = gtk_label_new ("Set a message, set a speed, and hit start.");
    gtk_container_add (GTK_CONTAINER (frame), label);
    gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
    gtk_widget_show (label);
    gtk_widget_show (frame);

    entry = gtk_entry_new ();
    gtk_entry_set_max_length (GTK_ENTRY (entry), 100);
    gtk_entry_set_text (GTK_ENTRY (entry), "Enter your message here.");
    tmp_pos = GTK_ENTRY (entry)->text_length;
    gtk_editable_insert_text (GTK_EDITABLE (entry), "", -1, &tmp_pos);
    gtk_editable_select_region (GTK_EDITABLE (entry),
			        0, GTK_ENTRY (entry)->text_length);
    gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
    gtk_widget_show (entry);

    adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 60.0, 1.0,
					      5.0, 0.0);
    delay = gtk_spin_button_new (adj, 0, 0);
    gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (delay), TRUE);
    gtk_box_pack_start (GTK_BOX (vbox), delay, FALSE, TRUE, 0);
    gtk_widget_show (delay);

    button = gtk_button_new_with_label ("Start");

    g_signal_connect (G_OBJECT (button), "clicked",
			      G_CALLBACK (delay_callback),
			      (gpointer) (delay));

    g_signal_connect (G_OBJECT (button), "clicked",
			      G_CALLBACK (enter_callback),
			      (gpointer) (entry));

    g_signal_connect (G_OBJECT (button), "clicked",
                      G_CALLBACK (check_dupe), NULL);

    g_signal_connect (G_OBJECT (button), "clicked",
                      G_CALLBACK (start_autotype), NULL);

    gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 10);
    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
    gtk_widget_grab_default (button);
    gtk_widget_show (button);

    button = gtk_button_new_with_label ("Stop");
    g_signal_connect (G_OBJECT (button), "clicked",
                      G_CALLBACK (stop_autotype), NULL);
    gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
    gtk_widget_show (button);

    frame = gtk_frame_new ("\nCreated by: Gary's Hood");
    label = gtk_label_new ("http://www.garyshood.com");
    gtk_container_add (GTK_CONTAINER (frame), label);
    gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
    gtk_widget_show (label);
    gtk_widget_show (frame);

    if((fp = fopen("/usr/bin/xvkbd","r"))==NULL && (fp = fopen("/usr/local/bin/xvkbd","r"))==NULL) {
    dialog = gtk_message_dialog_new (GTK_WINDOW (window),
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_ERROR,
                                     GTK_BUTTONS_CLOSE,
                                     "The program xvkbd was not detected. If it was installed, link xvkbd to /usr/bin/xvkbd or /usr/local/bin/xvkbd and restart this application.");

   gtk_window_set_title (GTK_WINDOW (dialog), "xvkbd not found");
   gtk_dialog_run (GTK_DIALOG (dialog));
   gtk_widget_destroy (dialog);
   }

   gtk_widget_show (window);
   gtk_main();
   return 0;

}
