/* 
 *    Programmed By: Mohammed Isam Mohammed [mohammed_isam1984@yahoo.com]
 *    Copyright 2013, 2014 (c)
 * 
 *    file: menu.c
 *    This file is part of Prime.
 *
 *    Prime 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.
 *
 *    Prime 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 Prime.  If not, see <http://www.gnu.org/licenses/>.
 */    

#include <stdio.h>
#include <stdlib.h>
#include "defs.h"
//#include "print.h"
#include "edit.h"
#include "sys/stat.h"
#include "find.h"
#include <pwd.h>

#define EOL	10

extern time_t tm;	//used to get system time to log it on shutdown
extern int getKey();

extern void cutMarked();
extern void cutOne();
extern void markAll();
extern void unMarkAll();
extern void setScreenColors(int FG, int BG);

/********************************************
 * This procedure shows the FILE menu under
 * the main menu bar. It also takes control
 * of the user input to navigate the menu
 * with the arrow keys and to select menu
 * items with ENTER. Pressing right or left
 * arrows navigate to next menu on the left
 * 'HELP' and the right 'EDIT' respectively.
 * ******************************************/
void showFileMenu(int visible) 
{
  int i, ch, fSelect = 0;
  int endme = 0;
  if(visible == YES) 
  {	//show the file menu
    //activeWindow = FILE_MENU;
    drawBox(3, 2, 9, 19, NULL, YES);
    setScreenColors(BLUE, BGWHITE);
    fprintf(stdout, "\e[4;3HNew directory ^N");
    setScreenColors(WHITE, BGBLUE);
    fprintf(stdout, "\e[5;3HOpen Location ^O");
    fprintf(stdout, "\e[6;3HExport Tree   ^E");
    fprintf(stdout, "\e[7;3HPrint         ^P");
    fprintf(stdout, "\e[8;3HExit          ^Q");
    fprintf(stdout, "\e[4;18H");
    while(!endme) 
    {				//wait for user input
      ch = getKey();
      switch(ch) 
      {
	case(ESC_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  refreshFileView();
	  refreshDirView();
	  endme = 1;
	  break;
	case(UP_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  //clear last selection
	  fprintf(stdout, "\e[%d;3H%s", fSelect+4, fileMenu[fSelect]);
	  fSelect--;
	  if(fSelect < 0) fSelect = fTotal-1;
	  setScreenColors(BLUE, BGWHITE);
	  //highlight new selection
	  fprintf(stdout, "\e[%d;3H%s", fSelect+4, fileMenu[fSelect]);
	  fprintf(stdout, "\e[%d;18H", fSelect+4);
	  break;
	case(DOWN_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  //clear last selection
	  fprintf(stdout, "\e[%d;3H%s", fSelect+4, fileMenu[fSelect]);
	  fSelect++;
	  if(fSelect >= fTotal) fSelect = 0;
	  setScreenColors(BLUE, BGWHITE);
	  //highlight new selection
	  fprintf(stdout, "\e[%d;3H%s", fSelect+4, fileMenu[fSelect]);
	  fprintf(stdout, "\e[%d;18H", fSelect+4);
	  break;
	//case(ALT_F_KEY)://hide file menu and return control to main program
	case('f'):
	 if(ALT) 
	 {
	  activeWindow = DIR_WIN;
	  setScreenColors(WHITE, BGBLUE);
	  refreshFileView();
	  refreshDirView();
	  return;
	 }
	  break;
	//case(ALT_E_KEY):	//navigate to Edit menu
	case('e'):
	 if(!ALT) break;
	case(RIGHT_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  fprintf(log_file, "Opening edit menu..\n");
	  refreshFileView();
	  refreshDirView();
	  showEditMenu(YES);
	  endme = 1;
	  break;
	//case(ALT_H_KEY):	//navigate to Help menu
	case('h'):
	 if(!ALT) break;
	case(LEFT_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  fprintf(log_file, "Opening help menu..\n");
	  refreshFileView();
	  refreshDirView();
	  showHelpMenu(YES);
	  endme = 1;
	  break;
	case(ENTER_KEY):
	  if(fSelect == 0) 
	  {	//user selected 'New directory'
	    char *res = (char *) malloc(MAX_DIR_NAME_LEN);
	    inputBox("Enter directory name to create:", "New Directory");
	    strcpy(res, input);
	    if(res != NULL) 
	    {
	      struct stat st;
	      if(stat(res, &st) == -1) 
	      {
		mkdir(res, 0700);//check if it doesn't exist, create it
		fprintf(log_file, "Creating directory %s..\n", res);
	      } 
	      else 
	      {
		msgBox("Directory already exists!", OK, ERROR);
		fprintf(log_file, "Directory %s already exists..\n", res);
	      }
	      scanDir(cwd);
	      refreshFileView();
	      refreshDirView();
	    } free(res);
	    endme = 1;
	    break;
	  }
	  if(fSelect == 2) 
	  {	//user selected 'Export Tree'
	    exportTree(YES);
	    setScreenColors(WHITE, BGBLUE);
	    scanDir(cwd);
	    endme = 1;
	    break;
	  }
	  if(fSelect == 1) 
	  {	//user selected 'Open location'
	    char *res = inputBox("Enter directory path to open:", 
				 "Open Location");
	    if(res != NULL) 
	    {
	      //************** check for '~'
	      char *tmp = (char *) malloc(MAX_DIR_NAME_LEN);
	      strcpy(tmp, res);
	      if(strchr(tmp, '~')) 
	      {
		char *tmp2 = (char *) malloc(MAX_DIR_NAME_LEN);
		strcpy(tmp2, res+((strchr(res, '~')+1)-res));
		struct passwd *pass;//will be used to find the home dir
		if((pass = getpwuid(geteuid())))
		  ;//printf("\nError: couldn't open home directory.\n");
		strcpy(tmp, pass->pw_dir);
		strcat(tmp, "/");
		strcat(tmp, tmp2);
		strcat(tmp, "\0");
		free(tmp2);
	      }//***************
	      scanDir(tmp);
	      refreshFileView();
	      refreshDirView();
	      endme = 1;
	      fprintf(log_file, "Opening '%s'..\n", tmp);
	      free(tmp);
	      break;
	    }
	  }
	  if(fSelect == 3) 
	  {	//user selected 'Print'
	    msgBox("Oops! This function is currently not implemented.", 
		   OK, INFO);
	    //fprintf(log_file, "Showing Print dialog box..\n");
	    //showPrintDialogBox();
	    refreshFileView();
	    refreshDirView();
	    endme = 1;
	    break;
	  }
	  if(fSelect == 4) 
	  {	//user selected 'Exit'
	    i = msgBox("Are you sure you want to exit?", YES | NO, CONFIRM);
	    if(i == YES) 
	    { 	//exit gracefully
	      fprintf(log_file, "Restoring terminal..\n");
	      restoreTerminal(); 
	      fprintf(log_file, "Closing files and Exiting Prime..\n");
	      setScreenColors(WHITE, BGBLACK);
	      clearScreen(); 
	      setScreenColors(WHITE, BGBLACK);
	      time_t tm = time(NULL);
	      fprintf(log_file, "System time and date: %s", ctime(&tm));
	      fcloseall();
	      //freePrinters();
	      exit(0); 
	    }
	  }
	  setScreenColors(WHITE, BGBLUE);
	  refreshFileView();
	  refreshDirView();
	  endme = 1;
	  break;
      }
    }
  } 
  else 
  {		//hide the file menu
    activeWindow = DIR_WIN;
    refreshFileView();
    refreshDirView();
    return;
  }
  fprintf(log_file, "Returning to main program from File Menu\n");
}

/********************************************
 * This procedure shows the EDIT menu under
 * the main menu bar. It also takes control
 * of the user input to navigate the menu
 * with the arrow keys and to select menu
 * items with ENTER. Pressing right or left
 * arrows navigate to next menu on the left
 * 'FILE' and the right 'HELP' respectively.
 * ******************************************/
void showEditMenu(int visible) 
{
  int i, ch, eSelect = 0;
  int endme = 0;
  if(visible == YES) 
  {	//show the file menu
    //activeWindow = EDIT_MENU;
    drawBox(3, 8, 11, 23, NULL, YES);
    setScreenColors(BLUE, BGWHITE);
    fprintf(stdout, "\e[4;9H%s", editMenu[0]);
    setScreenColors(WHITE, BGBLUE);
    for(i = 1; i < eTotal; i++) 
    {
      fprintf(stdout, "\e[%d;9H%s", i+4, editMenu[i]);
    }
    //fprintf( log_file, "Now in line 109 in showEditMenu()..\n" );
    fprintf(stdout, "\e[4;22H");
    while(!endme) 
    {				//wait for user input
      ch = getKey();
      switch(ch) 
      {
	case(ESC_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  refreshFileView();
	  refreshDirView();
	  endme = 1;
	  break;
	case(UP_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  //clear last selection
	  fprintf(stdout, "\e[%d;9H%s", eSelect+4, editMenu[eSelect]);
	  eSelect--;
	  if(eSelect < 0) eSelect = eTotal-1;
	  setScreenColors(BLUE, BGWHITE);
	  //highlight new selection
	  fprintf(stdout, "\e[%d;9H%s", eSelect+4, editMenu[eSelect]);
	  fprintf(stdout, "\e[%d;22H", eSelect+4);
	  break;
	case(DOWN_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  //clear last selection
	  fprintf(stdout, "\e[%d;9H%s", eSelect+4, editMenu[eSelect]);
	  eSelect++;
	  if(eSelect >= eTotal) eSelect = 0;
	  setScreenColors(BLUE, BGWHITE);
	  //highlight new selection
	  fprintf(stdout, "\e[%d;9H%s", eSelect+4, editMenu[eSelect]);
	  fprintf(stdout, "\e[%d;22H", eSelect+4);
	  break;
	//case(ALT_E_KEY)://hide edit menu and return control to main program
	case('e'):
	 if(ALT) 
	 {
	  activeWindow = DIR_WIN;
	  setScreenColors(WHITE, BGBLUE);
	  refreshFileView();
	  refreshDirView();
	  return;
	 }
	  break;
	//case(ALT_F_KEY):	//navigate to File menu
	case('f'):
	 if(!ALT) break;
	case(LEFT_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  fprintf(log_file, "Opening file menu..\n");
	  refreshFileView();
	  refreshDirView();
	  showFileMenu(YES);
	  endme = 1;
	  break;
	//case(ALT_H_KEY):	//navigate to Help menu
	case('h'):
	 if(!ALT) break;
	case(RIGHT_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  fprintf(log_file, "Opening help menu..\n");
	  refreshFileView();
	  refreshDirView();
	  showHelpMenu(YES);
	  endme = 1;
	  break;
	case(ENTER_KEY):
	  if(eSelect == 0) cutMarked();
	  if(eSelect == 1) copyMarked();
	  if(eSelect == 2) pasteMarked();
	  if(eSelect == 3) markAll();
	  if(eSelect == 4) unMarkAll();
	  if(eSelect == 5) clearSelection();
	  if(eSelect == 6) 
	  { 
	    findFile(); 
	    scanDir(cwd); 
	  }
	  if(eSelect == 7) {
	    showPropertiesDialog();
	    scanDir(cwd); 
	  }
	  setScreenColors(WHITE, BGBLUE);
	  //activeWindow = DIR_WIN;
	  refreshFileView();
	  refreshDirView();
	  refreshBottomView();
	  endme = 1;
	  break;
      }
    }
  } 
  else 
  {		//hide the edit menu
    activeWindow = DIR_WIN;
    refreshFileView();
    refreshDirView();
    return;
  }
  fprintf(log_file, "Returning to main program from Edit Menu\n");
}


/********************************************
 * This procedure shows the HELP menu under
 * the main menu bar. It also takes control
 * of the user input to navigate the menu
 * with the arrow keys and to select menu
 * items with ENTER. Pressing right or left
 * arrows navigate to next menu on the left
 * 'EDIT' and the right 'FILE' respectively.
 * ******************************************/
void showHelpMenu(int visible) 
{
  int i, ch, hSelect = 0;
  int endme = 0;
  if(visible == YES) 
  {	//show the file menu
    //activeWindow = HELP_MENU;
    drawBox(3, 14, 7, 31, NULL, YES);
    setScreenColors(BLUE, BGWHITE);
    fprintf(stdout, "\e[4;15H%s", helpMenu[0]);
    setScreenColors(WHITE, BGBLUE);
    for(i = 1; i < hTotal; i++) 
      fprintf(stdout, "\e[%d;15H%s", i+4, helpMenu[i]);
    fprintf(stdout, "\e[4;30H");
    while(!endme) 
    {				//wait for user input
      ch = getKey();
      switch(ch) 
      {
	case(ESC_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  refreshFileView();
	  refreshDirView();
	  endme = 1;
	  break;
	case(UP_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  //clear last selection
	  fprintf(stdout, "\e[%d;15H%s", hSelect+4, helpMenu[hSelect]);
	  hSelect--;
	  if(hSelect < 0) hSelect = hTotal-1;
	  setScreenColors(BLUE, BGWHITE);
	  //highlight new selection
	  fprintf(stdout, "\e[%d;15H%s", hSelect+4, helpMenu[hSelect]);
	  fprintf(stdout, "\e[%d;30H", hSelect+4);
	  break;
	case(DOWN_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  //clear last selection
	  fprintf(stdout, "\e[%d;15H%s", hSelect+4, helpMenu[hSelect]);
	  hSelect++;
	  if(hSelect >= hTotal) hSelect = 0;
	  setScreenColors(BLUE, BGWHITE);
	  //highlight new selection
	  fprintf(stdout, "\e[%d;15H%s", hSelect+4, helpMenu[hSelect]);
	  fprintf(stdout, "\e[%d;30H", hSelect+4);
	  break;
	//case(ALT_H_KEY)://hide help menu and return control to main program
	case('h'):
	 if(ALT) 
	 {
	  activeWindow = DIR_WIN;
	  setScreenColors(WHITE, BGBLUE);
	  refreshFileView();
	  refreshDirView();
	  return;
	 }
	  break;
	//case(ALT_F_KEY):	//navigate to File menu
	case('f'):
	 if(!ALT) break;
	case(RIGHT_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  fprintf(log_file, "Opening file menu..\n");
	  refreshFileView();
	  refreshDirView();
	  showFileMenu(YES);
	  endme = 1;
	  break;
	//case(ALT_E_KEY):	//navigate to Edit menu
	case('e'):
	 if(!ALT) break;
	case(LEFT_KEY):
	  setScreenColors(WHITE, BGBLUE);
	  fprintf(log_file, "Opening edit menu..\n");
	  refreshFileView();
	  refreshDirView();
	  showEditMenu(YES);
	  endme = 1;
	  break;
	case(ENTER_KEY):
	  if(hSelect == 0) 
	  {			//show README
	    fprintf(log_file, "Opening README..\n");
	    showReadMe();
	  } 
	  else if(hSelect == 2) 
	  {		//show About msgbox
	    fprintf(log_file, "Opening About dialog box..\n");
	    char *x = " Prime for GNU/Linux. \n Developed by \
Mohammed Isam, \n 2013, 2014. ";
	    msgBox(x, OK, INFO);
	  } 
	  else if(hSelect == 1) 
	  {	//show Quick reference
	    fprintf(log_file, "Opening Quick reference..\n");
	    drawBox(3, 5, 18, SCREEN_W-5, "Quick Reference", YES);
	    fprintf(stdout, "\e[4;7HBasic functions:");
	    fprintf(stdout, "\e[5;9HSPACEBAR: Toggle select/unselect");
	    fprintf(stdout, "\e[6;9HENTER: Navigate to directory");
	fprintf(stdout, "\e[7;9HTAB: Navigate between dir/file view windows");
	    fprintf(stdout, "\e[8;9HArrow keys: Navigate up/down");
	    fprintf(stdout, "\e[10;7HEditing:");
	    fprintf(stdout, "\e[11;9HDEL: Delete marked directories/files");
	    fprintf(stdout, "\e[12;9HCTRL+X: Cut marked directories/files");
	    fprintf(stdout, "\e[13;9HCTRL+C: Copy marked directories/files");
	    fprintf(stdout, "\e[14;9HCTRL+V: Paste marked directories/files");
	    fprintf(stdout, "\e[15;9HCTRL+F: Find files");
	    fprintf(stdout, "\e[16;9HCTRL+Q: Quit the program");
	    fprintf(stdout, "\e[17;7HPress any key to continue..");
	    do {;} while(!getKey());
	  }
	  setScreenColors(WHITE, BGBLUE);
	  drawBox(1,1, SCREEN_H, SCREEN_W," Prime for GNU/Linux ",NO);
	  drawMenuBar(2, 2, SCREEN_W-2);
	  refreshFileView();
	  refreshDirView();
	  refreshBottomView();
	  endme = 1;
	  break;
      }
    }
  } 
  else 
  {		//hide the help menu
    activeWindow = DIR_WIN;
    refreshFileView();
    refreshDirView();
    return;
  }
  fprintf(log_file, "Returning to main program from Help Menu\n");
}

/******************************************
 * this function shows a window with 
 * README file as its contents.
 * ****************************************/
void showReadMe() 
{
  int x = 2;
  int y = 2;
  int w = SCREEN_W-1;
  int h = SCREEN_H-1;
  FILE *README;
  char buf[4096*4];	//buffer to hold data
  int buf_len = 0;
  
  if(!(README = fopen("/usr/share/doc/Prime/README", "r"))) 
  {
   if(!(README = fopen("/usr/local/share/doc/Prime/README", "r"))) 
   {
    msgBox("Failed to open README file!.", OK, ERROR);
    fprintf(log_file, "Failed to open /usr/share/doc/Prime/README file..\n");
    scanDir(cwd);
    return;
   }
  }
  
  if(!(buf_len = fread(buf, sizeof(char), sizeof(buf), README))) 
  {
    msgBox("Failed to read the README file!.", OK, ERROR);
    fprintf(log_file, "Failed to read /usr/share/doc/Prime/README file..\n");
    scanDir(cwd);
    return;
  }
  
  drawBox(x, y, h, w, " README ", YES);
  
  y++; x++;
  int i = 0, j = x;
  int l = y;
  int lineStart[60];
  int firstVisLine = 0;
  int cnt = 0;
  int ch;
  char moreLines = 1;	//used as boolean to indicate if still more lines
  lineStart[0] = 0;
  
  fprintf(stdout, "\e[%d;%dH", j, l);
  //for(i = 0; i < buf_len; i++) {
  while(j <= (h-x+2)) 
  {
    if(buf[i] == EOL) 
    { 
      lineStart[++cnt] = i+1;
      l=y;
      fprintf(stdout, "\e[%d;%dH", ++j, l); 
    } 
    else 
    { 
      if(l >= (w-y+2)) 
      {
	lineStart[++cnt] = i;
	l=y;
	fprintf(stdout, "\e[%d;%dH", ++j, l);
      } 
      putchar(buf[i]); l++;
    }
    if(++i >= buf_len) break;
  }
  drawBox(x-1, y-1, h, w, " README ", NO);
  
  //if the output chars are less than the buffer length,
  //it means there are more lines to the output.
  if(i <= buf_len) 
  {
    goto readMore;
  } 
  else 
  {
    do {;} while(!getKey());
    goto end;
    return;
  }
  
readMore:
  while(1) 
  {
    ch = getKey();
    switch(ch) 
    {
      case(ENTER_KEY):
      case(SPACE_KEY):
      case(ESC_KEY):
	goto end;
	break;
      case(UP_KEY):
	if(firstVisLine == 0) break;	//can't go up--first line already
	firstVisLine--;
	break;
      case(DOWN_KEY):
	if(!moreLines) break;	//reached last line
	firstVisLine++;
	break;
    }	//end of switch
    //redraw the box with its contents
    drawBox(x-1, y-1, h, w, " README ", YES);
    j = x; l = y; cnt = firstVisLine; i = lineStart[firstVisLine];
    
    fprintf(stdout, "\e[%d;%dH", j, l);
    while(j <= (h-x+2)) 
    {
     if(buf[i] == EOL) 
     { 
      lineStart[++cnt] = i+1;
      l=y;
      fprintf(stdout, "\e[%d;%dH", ++j, l); 
     } 
     else 
     { 
      if(l >= (w-y+2)) 
      {
	lineStart[++cnt] = i;
	l=y;
	fprintf(stdout, "\e[%d;%dH", ++j, l);
      } 
      putchar(buf[i]); l++;
     }
     if(++i >= buf_len) break;
    }	//end of inner while
    if(i <= buf_len) { moreLines = 1; }
    else { moreLines = 0; }
    drawBox(x-1, y-1, h, w, " README ", NO);

  }	//end of outer while
end:
  fclose(README);
  //free(buf);
  drawMenuBar(2, 2, SCREEN_W-2);	//draw main menu bar
  scanDir(cwd);
  return;
}
