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

#include "defs.h"
#include "edit.h"
#include "kbd.h"
#include "options.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>


void swap_lines() 
{
  int tmp;
  tmp = sel_range_end.nline;
  sel_range_end.nline = sel_range_start.nline;
  sel_range_start.nline = tmp;
  tmp = sel_range_end.nchar;
  sel_range_end.nchar = sel_range_start.nchar;
  sel_range_start.nchar = tmp;
}

void swap_chars() 
{
  int tmp;
  tmp = sel_range_end.nchar;
  sel_range_end.nchar = sel_range_start.nchar;
  sel_range_start.nchar = tmp;
}

/*****************************************
 * Clears the selected range. This is
 * helpful when exiting from the select
 * mode (like using arrow keys after
 * releasing SHIFT).
 * ***************************************/
void clear_selected_range() 
{
  
}

void editMenu_DeleteLine() 
{
  deleteLine();
}

/*****************************************
 * Toggles select mode ON/OFF. Select mode
 * is useful when running under X, to
 * emulate SHIFT-selection.
 * ***************************************/
void editMenu_ToggleSelectMode() 
{
  if(X_IS_RUNNING) 
  {
    SELECTING = !SELECTING;
    refreshBottomView();
    if(SELECTING) 
    {
      sel_range_start.nline = firstVisLine+selectedLine;
      sel_range_start.nchar = selectedChar;
      sel_range_end.nline = firstVisLine+selectedLine;
      sel_range_end.nchar = selectedChar;
    }
  } 
  else 
  {
    msgBox("The select mode is only available under X.\nUse SHIFT to select text.", OK, INFO);
    refreshView();
  }
}

/*****************************************
 * Copies selection to clipboard.
 * ***************************************/
void editMenu_Copy() 
{
 if(SELECTING || SELECTED) 
 {
  int i, j, k, l, pos = 0;
  strcpy(clipboard, "");
  //swap the select range boundaries if needed
  int swap = 0;
  if(sel_range_start.nline > sel_range_end.nline) { swap = 1; swap_lines(); }
  else if(sel_range_start.nline == sel_range_end.nline &&
	  sel_range_start.nchar > sel_range_end.nchar) 
  { swap = 2; swap_chars(); }

  total_lines_in_clipboard = 0;
  for(j = sel_range_start.nline; j <= sel_range_end.nline; j++) 
  {
    if(j == sel_range_start.nline) 
    { 
      k = sel_range_start.nchar;
      l = totalCharsInLine[j]-1;
    } 
    else 
    {
      k = 0;
      if(j == sel_range_end.nline) l = sel_range_end.nchar-1;
      else l = totalCharsInLine[j]-1;
    }
    for(i = k; i <= l; i++) 
    {
      clipboard[pos++] = lines[j][i*4];
      clipboard[pos++] = lines[j][i*4+1];
      clipboard[pos++] = lines[j][i*4+2];
      clipboard[pos++] = lines[j][i*4+3];
    }
    if(!LINE_IS_LINKED[j]) 
    { 
      clipboard[pos++] = '\n';
      clipboard[pos++] = ' ';
      clipboard[pos++] = ' ';
      clipboard[pos++] = ' ';
      total_lines_in_clipboard++;
    }
  }//end for
  clipboard[pos-1] = '\0';
  //total_lines_in_clipboard = sel_range_end.nline-sel_range_start.nline+1;
  //total_lines_in_clipboard++;
  CLIPBOARD_IS_EMPTY = 0;
  
  if(swap == 1) swap_lines();//return them back to normal
  if(swap == 2) swap_chars();//return them back to normal
  //strcpy(clipboard, selected_text);
 }//end if
}//end function

/*********************************************
 * Copies selection to clipboard then cuts it.
 * *******************************************/
void editMenu_Cut() 
{
  if(SELECTING || SELECTED) 
  {
    editMenu_Copy();
    remove_selected_text(1);
  }
}//end minoMenu_Cut()

/*****************************************
 * Removes the selected range of text.
 * ***************************************/
void remove_selected_text(bool RECORD) 
{
  int i, j, posLine, posLine2, posChar, posChar2;
  int swap = 0;
  if(sel_range_start.nline > sel_range_end.nline) { swap = 1; swap_lines(); }
  else if(sel_range_start.nline == sel_range_end.nline &&
	  sel_range_start.nchar > sel_range_end.nchar) { swap = 2; swap_chars(); }

  if(RECORD) 
  {
    if(RECORDING_UNDO_ACTION) finish_undo_action();
    //if(!RECORDING_UNDO_ACTION) {
      int tmp1, tmp2, tmp3;
      tmp1 = firstVisLine; tmp2 = selectedLine; tmp3 = selectedChar;
      firstVisLine = 0; selectedLine = sel_range_start.nline;
      selectedChar = sel_range_start.nchar;
      begin_undo_action(UNDO_ACTION_DELETE);
      firstVisLine = tmp1; selectedLine = tmp2; selectedChar = tmp3;
    //}
  }//end RECORD
  
  posLine = sel_range_start.nline;
  posLine2 = sel_range_end.nline;
  posChar = sel_range_start.nchar;
  posChar2 = sel_range_end.nchar;
  
  if(posLine == posLine2) 
  {//if #1
    //if deleting in one line
    int refresh = 0;
    if(posChar2 == strlen(lines[posLine])/4) 
    {//if #2
      //if deleting upto the last character in line
      if(RECORD) 
      {
	int t; t = selectedChar;
	selectedChar = sel_range_start.nchar;
	for(i = posChar; i <= posChar2; i++) 
	{ 
	  add_to_undo_action(lines[posLine]+(i*4));
	  //add_to_undo_action(lines[posLine][i*4+1]);
	  //add_to_undo_action(lines[posLine][i*4+2]);
	  //add_to_undo_action(lines[posLine][i*4+3]);
	  selectedChar++; 
	}
	selectedChar = t;
      }
      lines[posLine][posChar*4] = '\0';
      //if the line is linked to next line, grab thos chars
      //and append them here.. go on until we hit a non-linked line
      int i = posLine;
      while(LINE_IS_LINKED[posLine]) 
      {
	refresh = 1;
	int j = MAX_CHARS_PER_LINE-(strlen(lines[posLine])/4);
	strncat(lines[posLine], lines[posLine+1], j*4);
	totalCharsInLine[posLine] = strlen(lines[posLine])/4;
	//if we appended all the next line, remove it
	if(strlen(lines[posLine+1])/4 <= j) 
	{
	  LINE_IS_LINKED[posLine] = 0;
	  for(j = posLine+1; j < totalLines-1; j++) 
	  {
	    strcpy(lines[j], lines[j+1]);
	    totalCharsInLine[j] = strlen(lines[j])/4;
	    LINE_IS_LINKED[j] = LINE_IS_LINKED[j+1];
	  }//end for
	  totalLines--; break;
	}//end if
	strcpy(lines[posLine+1], lines[posLine+1]+(j*4));
	totalCharsInLine[posLine+1] = strlen(lines[posLine+1])/4;
	posLine++;
      }//end while
      posLine = i;
      totalCharsInLine[posLine] = strlen(lines[posLine])/4;
      selectedChar = posChar2;
      if(RECORD) finish_undo_action();
      selectedChar = posChar;
    } 
    else 
    {
      //if deleting in the middle of the line
      if(RECORD) 
      {
	int t; t = selectedChar;
	selectedChar = sel_range_start.nchar;
	for(i = posChar; i <= posChar2; i++) 
	//{ add_to_undo_action(lines[posLine][i]); selectedChar++; }
	{ 
	  add_to_undo_action(lines[posLine]+(i*4));
	  //add_to_undo_action(lines[posLine][i*4+1]);
	  //add_to_undo_action(lines[posLine][i*4+2]);
	  //add_to_undo_action(lines[posLine][i*4+3]);
	  selectedChar++; 
	}
	selectedChar = t;
      }
      for(i = 0; i <= (strlen(lines[posLine])/4)-posChar2; i++) 
      {
	lines[posLine][(posChar*4)+(i*4)] = 
	    lines[posLine][(i*4)+(posChar2*4)];
      }
      lines[posLine][(posChar*4)+(i*4)] = '\0';
      totalCharsInLine[posLine] = strlen(lines[posLine])/4;
      
      //if the line is linked to next line, grab thos chars
      //and append them here.. go on until we hit a non-linked line
      int i = posLine;
      while(LINE_IS_LINKED[posLine]) 
      {
	refresh = 1;
	int j = MAX_CHARS_PER_LINE-(strlen(lines[posLine])/4);
	strncat(lines[posLine], lines[posLine+1], j*4);
	totalCharsInLine[posLine] = strlen(lines[posLine])/4;
	//if we appended all the next line, remove it
	if(strlen(lines[posLine+1])/4 <= j) 
	{
	  LINE_IS_LINKED[posLine] = 0;
	  for(j = posLine+1; j < totalLines-1; j++) 
	  {
	    strcpy(lines[j], lines[j+1]);
	    totalCharsInLine[j] = strlen(lines[j])/4;
	    LINE_IS_LINKED[j] = LINE_IS_LINKED[j+1];
	  }//end for
	  totalLines--; break;
	}//end if
	strcpy(lines[posLine+1], lines[posLine+1]+(j*4));
	totalCharsInLine[posLine+1] = strlen(lines[posLine+1])/4;
	posLine++;
      }//end while
      posLine = i;

      selectedChar = posChar2;
      if(RECORD) finish_undo_action();
      selectedChar = posChar; j = posChar;
    }//end if #2
    SELECTING = 0; SELECTED = 0;
    FILE_STATE = MODIFIED;
    
    checkTabsInLine(posLine);
    //adjust the view
    selectedLine = posLine-firstVisLine;
    if(selectedLine < 0) 
    {
      firstVisLine = posLine; selectedLine = 0;
    } 
    else if(selectedLine >= totalVisLines) 
    {
      firstVisLine = posLine-totalVisLines-1;
      selectedLine = totalVisLines-1;
    }
    
    if(LINE_IS_LINKED[posLine] || refresh) { refreshView(); }
    else  refreshSelectedLine();
  } 
  else 
  {
    //if deleting multiple lines
    i = posLine; j = posChar;
    //if(posLine2 == totalLines-1) {//if deleting upto last line
    if(posLine2 == totalLines-1 && posChar2 >= strlen(lines[posLine2])/4) 
    {//if deleting upto last line
      if(RECORD) 
      {
	int t = selectedChar; int t2 = firstVisLine;
	while(1) 
	{
	  add_to_undo_action(lines[i]+j++);
	  //add_to_undo_action(lines[i][j++]);
	  //add_to_undo_action(lines[i][j++]);
	  //add_to_undo_action(lines[i][j++]);
	  selectedChar++;
	  if(j >= strlen(lines[i])) 
	  { add_to_undo_action("\n   "); i++; j = 0; selectedChar++; firstVisLine++; }
	  if(i >= totalLines) break;
	}
	selectedChar = t; firstVisLine = t2;
	if(undo_text[last_undo_action][strlen(undo_text[last_undo_action])-4]
	    == '\n') undo_action_end[last_undo_action].nchar = 0;
	undo_action_end[last_undo_action].nline = totalLines;
      }//finish RECORD
      lines[posLine][posChar*4] = '\0';
      totalCharsInLine[posLine] = strlen(lines[posLine])/4;
      totalLines -= totalLines-posLine-1;
      i = posLine; j = posChar;
    } 
    else 
    {	//if deleting in the middle of lines
      i = posLine; j = posChar;
	  int k, l;
	  if(RECORD) 
	  {
	    int t = selectedChar; int t2 = firstVisLine;
	    for(k = posChar; k < strlen(lines[posLine])/4; k++)
	    { add_to_undo_action(lines[posLine]+(k*4)); selectedChar++; }
	    add_to_undo_action("\n   "); 
	    selectedChar++; //selectedChar = 0;
	    for(l = posLine+1; l < posLine2; l++) 
	    {
	      for(k = 0; k < strlen(lines[l])/4; k++)
	      { add_to_undo_action(lines[l]+(k*4)); selectedChar++; }
	      add_to_undo_action("\n   "); 
	      selectedChar++; //selectedChar = 0;
	    }
	    if(posChar2 != 0)
	      for(k = 0; k < posChar2; k++)
	      { add_to_undo_action(lines[posLine2]+(k*4)); selectedChar++; }
	    selectedChar = t; firstVisLine = t2;
	    if(undo_text[last_undo_action][strlen(undo_text[last_undo_action])-4]
		== '\n') undo_action_end[last_undo_action].nchar = 0;
	  }

	  strcpy(lines[posLine]+(posChar*4), lines[posLine2]+(posChar2*4));
	  totalCharsInLine[posLine] = strlen(lines[posLine])/4;
	  LINE_IS_LINKED[posLine] = LINE_IS_LINKED[posLine2];
	  for(k = 1; k < totalLines-(posLine2-posLine); k++) 
	  {
	    strcpy(lines[posLine+k], lines[posLine2+k]);
	    totalCharsInLine[posLine+k] = strlen(lines[posLine+k])/4;
	    LINE_IS_LINKED[posLine+k] = LINE_IS_LINKED[posLine2+k];
	  }
	  totalLines -= (posLine2-posLine);
	  LINE_IS_LINKED[posLine] = 0;
	  
	  checkAllTabs();
	  //if the new formed line is too long, see if it is
	  //linked.. if it is, append the lines until we hit
	  //a non linked line.. otherwise create new line and
	  //dump the extra chars into it..
	  if(strlen(lines[posLine])/4 > MAX_CHARS_PER_LINE) 
	  {//if1
	    if(LINE_IS_LINKED[posLine]) 
	    {//if2
	      char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4);
	      while(LINE_IS_LINKED[posLine]) 
	      {
		int l = (strlen(lines[posLine])/4)-MAX_CHARS_PER_LINE;
		strcpy(tmp, lines[posLine+1]);
		strcpy(lines[posLine+1], lines[posLine]+(MAX_CHARS_PER_LINE*4));
		lines[posLine][MAX_CHARS_PER_LINE*4] = '\0';
		totalCharsInLine[posLine] = strlen(lines[posLine])/4;
		strcat(lines[posLine+1], tmp);
		totalCharsInLine[posLine+1] = strlen(lines[posLine+1])/4;
		posLine++; if(posLine >= totalLines) break;
	      }//end while
	      free(tmp);
	    } 
	    else 
	    {
	      for(i = totalLines; i > posLine+1; i--) 
	      {
		strcpy(lines[i], lines[i-1]);
		totalCharsInLine[i] = strlen(lines[i])/4;
		LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
	      }
	      strcpy(lines[posLine+1], lines[posLine]+(MAX_CHARS_PER_LINE*4));
	      lines[posLine][MAX_CHARS_PER_LINE*4] = '\0';
	      totalCharsInLine[posLine] = strlen(lines[posLine])/4;
	      totalCharsInLine[posLine+1] = strlen(lines[posLine+1])/4;
	      LINE_IS_LINKED[posLine] = 1;
	      totalLines++;
	      posLine++;
	    }//end if2
	  }//end if1

      }
      
    SELECTING = 0; SELECTED = 0;
    FILE_STATE = MODIFIED;
    posChar = j; posLine = i;
    selectedChar = posChar;
    //adjust the view
    selectedLine = posLine-firstVisLine;
    if(selectedLine < 0) 
    {
      firstVisLine = posLine; selectedLine = 0;
    } 
    else if(selectedLine >= totalVisLines) 
    {
      firstVisLine = posLine-totalVisLines-1;
      selectedLine = totalVisLines-1;
    }
    if(RECORD) finish_undo_action();
    refreshView();
  }//end if #1

  if(swap == 1) swap_lines();//return them back to normal
  if(swap == 2) swap_chars();//return them back to normal
}

/*****************************************
 * Pastes whatever in the clipboard into
 * the current position.
 * ***************************************/
void editMenu_Paste() 
{
  if(CLIPBOARD_IS_EMPTY) return;
  int i = 0;
  int j = firstVisLine+selectedLine;
  int k = selectedChar;
  int l;
  if((total_lines_in_clipboard+totalLines) > MAX_LINES) l = MAX_LINES - totalLines;
  else l = total_lines_in_clipboard;
  l--;
  
  if(RECORDING_UNDO_ACTION) finish_undo_action();
  begin_undo_action(UNDO_ACTION_INSERT);
  
  //if pasting in the middle of a line, save the rest of the line
  char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4); 
  strcpy(tmp, "");
  int n;
  if(k < strlen(lines[j])) 
  { 
    strcpy(tmp, lines[j]+(k*4));
  }
  n = l;
  
  for(i = totalLines+l; i > j+l; i--) 
  {
    strcpy(lines[i], lines[i-l]);
    totalCharsInLine[i] = strlen(lines[i])/4;
    LINE_IS_LINKED[i] = LINE_IS_LINKED[i-l];
  }
  i = 0;
  l += j+1;
  
  while(j <= l) 
  {
    if(k >= MAX_CHARS_PER_LINE) 
    { 
      int m;
      for(m = totalLines; m > j+1; m--) 
      {
	strcpy(lines[m], lines[m-1]);
	totalCharsInLine[m] = strlen(lines[m])/4;
	LINE_IS_LINKED[m] = LINE_IS_LINKED[m-1];
      } totalLines++; n++;
      LINE_IS_LINKED[j] = 1;
      lines[j][k*4] = '\0';
      totalCharsInLine[j] = strlen(lines[j])/4;
      j++; k = 0; 
    }
    if(clipboard[i] == '\0') { lines[j][k*4] = '\0'; break; }
    add_to_undo_action(clipboard+i);
    if(clipboard[i] == '\n') 
    { 
      LINE_IS_LINKED[j] = 0;
      lines[j][k*4] = '\0'; 
      totalCharsInLine[j] = strlen(lines[j])/4;
      j++; k = 0; i+=4; selectedLine++;
    } else { 
      lines[j][k*4] = clipboard[i];
      lines[j][k*4+1] = clipboard[i+1];
      lines[j][k*4+2] = clipboard[i+2];
      lines[j][k*4+3] = clipboard[i+3];
      k+=4; i+=4; 
    }
  }//end while
  totalLines += n; //total_lines_in_clipboard;
  selectedLine += n;
  if(k == 0) selectedLine--;
  
  //if there is text in tmp, append it to the last pasted line
  if(strlen(tmp)) 
  {
    //j = firstVisLine+selectedLine;
    strcat(lines[j], tmp);
      
    if(strlen(lines[j])/4 > MAX_CHARS_PER_LINE) 
    {
      for(i = totalLines; i > j+1; i--) 
      {
	strcpy(lines[i], lines[i-1]);
	totalCharsInLine[i] = strlen(lines[i])/4;
	LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
      }
      strcpy(lines[j+1], lines[j]+(MAX_CHARS_PER_LINE*4));
      lines[j][MAX_CHARS_PER_LINE*4] = '\0';
      LINE_IS_LINKED[j] = 1;
      totalCharsInLine[j+1] = strlen(lines[j+1])/4;
      totalLines++;
    }
    free(tmp);
  }
  
  totalCharsInLine[j] = strlen(lines[j])/4;
  checkTabsInLine(j);
  //adjust the view
  if(selectedLine > totalVisLines-1) 
  {
    firstVisLine += (selectedLine-totalVisLines+1);
    selectedLine -= (selectedLine-totalVisLines+1);
  }
  if(totalLines <= totalVisLines) 
  {
    firstVisLine = 0; selectedLine = totalLines-1;
  } 
  else if((totalLines-j) < totalVisLines) 
  {
    firstVisLine = totalLines-totalVisLines;
    selectedLine = totalVisLines-(totalLines-j)-1;
  } //else { firstVisLine = totalLines-j; selectedLine = 0; }
  selectedChar = k;
  finish_undo_action();
  SELECTED = 0; SELECTING = 0;
  FILE_STATE = MODIFIED;
  refreshView();
}

/*****************************************
 * 
 * ***************************************/
void editMenu_SelectAll() 
{
  SELECTING = 1;
  sel_range_start.nline = 0;
  sel_range_end.nline = totalLines-1;
  sel_range_start.nchar = 0;
  sel_range_end.nchar = strlen(lines[totalLines-1]);
  if(sel_range_end.nchar < 0) sel_range_end.nchar = 0;
  if(totalLines <= totalVisLines) 
  {
    selectedLine = totalLines-1;
    selectedChar = totalCharsInLine[selectedLine];
  } 
  else 
  {
    firstVisLine = totalLines-totalVisLines;
    selectedLine = totalVisLines-1;
    selectedChar = totalCharsInLine[firstVisLine+selectedLine];
  }
  refreshView();
  SELECTING = 0;
  SELECTED = 1;
  refreshBottomView();
}

/************************************************
 * Undo the last action done. Last action can be:
 * UNDO_ACTION_REPLACE: The user replaced a
 * 			character with INSERT on
 * UNDO_ACTION_INSERT: The user typed regularly
 * UNDO_ACTION_DELETE: The user deleted using
 * 			DEL or BACKSPACE
 * **********************************************/
void editMenu_Undo() 
{
  if(last_undo_action < 0) return;
  if(RECORDING_UNDO_ACTION) finish_undo_action();
  if(undo_action[last_undo_action] == UNDO_ACTION_REPLACE) 
  {
    int i = strlen(undo_text[last_undo_action])/4;
    int j = strlen(undo_text_replace[last_undo_action])/4;
    int k, l = 0;
    if(i == j) 
    {//if #2
      for(k = undo_action_start[last_undo_action].nchar;
	  k <= undo_action_end[last_undo_action].nchar; k++)
	  {
	  lines[undo_action_start[last_undo_action].nline][k*4] =
		undo_text[last_undo_action][l*4];
	  lines[undo_action_start[last_undo_action].nline][k*4+1] =
		undo_text[last_undo_action][l*4+1];
	  lines[undo_action_start[last_undo_action].nline][k*4+2] =
		undo_text[last_undo_action][l*4+2];
	  lines[undo_action_start[last_undo_action].nline][k*4+3] =
		undo_text[last_undo_action][l*4+3];
		l++;
	  }
	  if(k == strlen(lines[undo_action_start[last_undo_action].nline])/4)
	    lines[undo_action_start[last_undo_action].nline][k*4] = '\0';
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    } else if(i < j) {
      //THE REPLACEMENT TEXT IS LONGER THAN THE ORIGINAL TEXT
      for(k = undo_action_start[last_undo_action].nchar;
	  k < undo_action_start[last_undo_action].nchar+i; k++)
	  //lines[undo_action_start[last_undo_action].nline][k] =
	//	undo_text[last_undo_action][l++];
	  {
	    lines[undo_action_start[last_undo_action].nline][k*4] =
		undo_text[last_undo_action][l*4];
	    lines[undo_action_start[last_undo_action].nline][k*4+1] =
		undo_text[last_undo_action][l*4+1];
	    lines[undo_action_start[last_undo_action].nline][k*4+2] =
		undo_text[last_undo_action][l*4+2];
	    lines[undo_action_start[last_undo_action].nline][k*4+3] =
		undo_text[last_undo_action][l*4+3];
	    l++;
	  }
      l = k;
      for(k = l; k < totalCharsInLine[undo_action_start[last_undo_action].nline]-(j-i); k++)
	  //lines[undo_action_start[last_undo_action].nline][k] =
	   // lines[undo_action_start[last_undo_action].nline][k+j-i];
	  {
	    lines[undo_action_start[last_undo_action].nline][k*4] =
		undo_text[last_undo_action][(k+j-i)*4];
	    lines[undo_action_start[last_undo_action].nline][k*4+1] =
		undo_text[last_undo_action][(k+j-i)*4+1];
	    lines[undo_action_start[last_undo_action].nline][k*4+2] =
		undo_text[last_undo_action][(k+j-i)*4+2];
	    lines[undo_action_start[last_undo_action].nline][k*4+3] =
		undo_text[last_undo_action][(k+j-i)*4+3];
	  }
      lines[undo_action_start[last_undo_action].nline][k*4] = '\0';
      totalCharsInLine[undo_action_start[last_undo_action].nline] =
	  strlen(lines[undo_action_start[last_undo_action].nline])/4;
      //check to see if the line is linked..
      l = undo_action_start[last_undo_action].nline;
      while(LINE_IS_LINKED[l]) 
      {
	j = MAX_CHARS_PER_LINE-(strlen(lines[l])/4);
	strncat(lines[l], lines[l+1], j*4);
	totalCharsInLine[l] = strlen(lines[l])/4;
	//if line is short remove it
	if(strlen(lines[l+1])/4 < j) {
	  for(i = l+1; i < totalLines-1; i++) 
	  {
	    strcpy(lines[i], lines[i+1]);
	    totalCharsInLine[i] = strlen(lines[i])/4;
	    LINE_IS_LINKED[i] = LINE_IS_LINKED[i+1];
	  } totalLines--;
	  LINE_IS_LINKED[l] = 0; break;
	}
	strcpy(lines[l+1], lines[l+1]+(j*4));
	totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	l++; if(l >= totalLines) break;
      }
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    //////////////////////////////////////////////////////
    } else {
      //THE REPLACEMENT TEXT IS SHORTER THAN THE ORIGINAL TEXT
      l = undo_action_start[last_undo_action].nchar+i-j;
      int m = (strlen(lines[undo_action_start[last_undo_action].nline])/4)+i-j;
      for(k = m; k > l; k--)
      {
	  lines[undo_action_start[last_undo_action].nline][k*4] =
	    lines[undo_action_start[last_undo_action].nline][(k-(i-j))*4];
	  lines[undo_action_start[last_undo_action].nline][k*4+1] =
	    lines[undo_action_start[last_undo_action].nline][(k-(i-j))*4+1];
	  lines[undo_action_start[last_undo_action].nline][k*4+2] =
	    lines[undo_action_start[last_undo_action].nline][(k-(i-j))*4+2];
	  lines[undo_action_start[last_undo_action].nline][k*4+3] =
	    lines[undo_action_start[last_undo_action].nline][(k-(i-j))*4+3];
      }
      lines[undo_action_start[last_undo_action].nline][(m+1)*4] = '\0';
      l = 0;
      for(k = undo_action_start[last_undo_action].nchar;
	  k <= undo_action_start[last_undo_action].nchar+i-j; k++)
	  //lines[undo_action_start[last_undo_action].nline][k] =
	//	undo_text[last_undo_action][l++];
	  {
	    lines[undo_action_start[last_undo_action].nline][k*4] =
		undo_text[last_undo_action][l*4];
	    lines[undo_action_start[last_undo_action].nline][k*4+1] =
		undo_text[last_undo_action][l*4+1];
	    lines[undo_action_start[last_undo_action].nline][k*4+2] =
		undo_text[last_undo_action][l*4+2];
	    lines[undo_action_start[last_undo_action].nline][k*4+3] =
		undo_text[last_undo_action][l*4+3];
	    l++;
	  }
      //if the line becomes too long, check to see if the line is 
      //linked. If it is, grab characters from the next line and
      //append them here.. continue till we hit a nonlinked line.
      l = undo_action_start[last_undo_action].nline;
      if(totalCharsInLine[l] > MAX_CHARS_PER_LINE) 
      {//if1
	if(LINE_IS_LINKED[l]) 
	{//if2
	  char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4);
	  while(LINE_IS_LINKED[l]) 
	  {
	    strcpy(tmp, lines[l+1]);
	    strcpy(lines[l+1], lines[l]+(MAX_CHARS_PER_LINE*4));
	    strcat(lines[l+1], tmp);
	    lines[l][MAX_CHARS_PER_LINE*4] = '\0';
	    l++; if(l >= totalLines) break;
	  }//end while
	  //check the last line is not too long
	  if(totalCharsInLine[--l]/4 > MAX_CHARS_PER_LINE) 
	  {
	    //make some room
	    for(i = totalLines; i > l+1; i++) 
	    {
	      strcpy(lines[i], lines[i-1]);
	      totalCharsInLine[i] = strlen(lines[i])/4;
	      LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
	    }
	    strcpy(lines[l+1], lines[l]+(MAX_CHARS_PER_LINE*4));
	    lines[l][MAX_CHARS_PER_LINE*4] = '\0';
	    LINE_IS_LINKED[l] = 1;
	    totalCharsInLine[l] = strlen(lines[l])/4;
	    totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	  }
	  free(tmp);
	} 
	else 
	{
	}//end if2
      }//end if1
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    }//end if #2
    
    l = undo_action_start[last_undo_action].nline;
    selectedChar = undo_action_start[last_undo_action].nchar;
    //adjust the view
    selectedLine = l-firstVisLine;
    if(selectedLine < 0) 
    {
      firstVisLine = l; selectedLine = 0;
    } 
    else if(selectedLine >= totalVisLines) 
    {
      firstVisLine = l-totalVisLines;
      selectedLine = totalVisLines-1;
    }
    /*if(firstVisLine > l) { firstVisLine = l; selectedLine = 0; }
    if(firstVisLine+selectedLine < l) { firstVisLine = l-totalVisLines-1; selectedLine = totalVisLines-1; }
    if(selectedLine+firstVisLine != l) selectedLine = l-firstVisLine;*/
    last_undo_action--;
    refreshView();
  } else if(undo_action[last_undo_action] == UNDO_ACTION_INSERT) {
    sel_range_start.nline = undo_action_start[last_undo_action].nline;
    sel_range_end.nline = undo_action_end[last_undo_action].nline;
    sel_range_start.nchar = undo_action_start[last_undo_action].nchar;
    sel_range_end.nchar = undo_action_end[last_undo_action].nchar;
    remove_selected_text(0);
    last_undo_action--;
    refreshView();
  } else if(undo_action[last_undo_action] == UNDO_ACTION_DELETE) {
    int l, i = undo_action_end[last_undo_action].nline -
	    undo_action_start[last_undo_action].nline;
    if(i) 
    {
      for(l = totalLines+i; l >= undo_action_start[last_undo_action].nline+i; l--) 
      {
       strcpy(lines[l], lines[l-i]);
       totalCharsInLine[l] = strlen(lines[l])/4;
       LINE_IS_LINKED[l] = LINE_IS_LINKED[l-i];
      }
    } 
    else 
    {
      if(strlen(lines[undo_action_start[last_undo_action].nline])+
	 strlen(undo_text[last_undo_action]) > MAX_CHARS_PER_LINE*4) {
	for(l = totalLines; l > undo_action_start[last_undo_action].nline; l--) 
	{
	  strcpy(lines[l], lines[l-1]);
	  totalCharsInLine[l] = strlen(lines[l])/4;
	  LINE_IS_LINKED[l] = LINE_IS_LINKED[l-1];
	}//end for
	totalLines++; strcpy(lines[l+1], "\0");
      //LINE_IS_LINKED[l+1] = 0;
      }//end inner if
    }
    int j = undo_action_start[last_undo_action].nchar;
    int k = undo_action_end[last_undo_action].nchar;
    if(i == 0) 
    {//deletion in the same line
      if(strlen(lines[undo_action_start[last_undo_action].nline])+
	 strlen(undo_text[last_undo_action]) > MAX_CHARS_PER_LINE*4) 
      {
	char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4);
	strcpy(tmp, lines[undo_action_start[last_undo_action].nline]+
		    (undo_action_start[last_undo_action].nchar*4));
	int m = MAX_CHARS_PER_LINE-undo_action_end[last_undo_action].nchar;
	memset(lines[undo_action_start[last_undo_action].nline], 
	       ' ', (undo_action_end[last_undo_action].nchar+1)*4);
	lines[undo_action_start[last_undo_action].nline]
	       [undo_action_end[last_undo_action].nchar*4] = '\0';
	strncat(lines[undo_action_start[last_undo_action].nline], tmp, m*4);
	//strncpy(lines[undo_action_start[last_undo_action].nline]+
	  //     undo_action_end[last_undo_action].nchar, tmp, m);
	tmp += m*4;
	strcpy(lines[undo_action_start[last_undo_action].nline+1], tmp);
	totalCharsInLine[undo_action_start[last_undo_action].nline+1] = 
	   strlen(lines[undo_action_start[last_undo_action].nline+1])/4;
	LINE_IS_LINKED[undo_action_start[last_undo_action].nline] = 1;
	tmp -= m*4;
	free(tmp);
      } 
      else 
      {
	for(i = (strlen(lines[undo_action_start[last_undo_action].nline])/4)+k-j;
	  i >= k; i--)
	    {
	      lines[undo_action_start[last_undo_action].nline][i*4] =
	      lines[undo_action_start[last_undo_action].nline][(i-(k-j))*4];
	      lines[undo_action_start[last_undo_action].nline][i*4+1] =
	      lines[undo_action_start[last_undo_action].nline][(i-(k-j))*4+1];
	      lines[undo_action_start[last_undo_action].nline][i*4+2] =
	      lines[undo_action_start[last_undo_action].nline][(i-(k-j))*4+2];
	      lines[undo_action_start[last_undo_action].nline][i*4+3] =
	      lines[undo_action_start[last_undo_action].nline][(i-(k-j))*4+3];
	    }
	//shiftTabsInLine(undo_action_start[last_undo_action].nline, j, k-j);
      }
      totalCharsInLine[undo_action_start[last_undo_action].nline] = 
	   strlen(lines[undo_action_start[last_undo_action].nline])/4;
    } 
    else 
    {
      strcpy(lines[undo_action_end[last_undo_action].nline]+(k*4), 
	   lines[undo_action_start[last_undo_action].nline]+(j*4));
    }
    l = undo_action_start[last_undo_action].nline;
    i = 0;
    while(l <= undo_action_end[last_undo_action].nline) 
    {
      if(undo_text[last_undo_action][i] == '\n') 
      { 
	lines[l][j] = '\0'; totalCharsInLine[l] = strlen(lines[l])/4;
	LINE_IS_LINKED[l] = 0; l++; j = 0; i+=4;
      } 
      else 
      {
	lines[l][j] = undo_text[last_undo_action][i];
	lines[l][j+1] = undo_text[last_undo_action][i+1];
	lines[l][j+2] = undo_text[last_undo_action][i+2];
	lines[l][j+3] = undo_text[last_undo_action][i+3];
	i+=4; j+=4;
      }
      
      if(j/4 > MAX_CHARS_PER_LINE) { LINE_IS_LINKED[l] = 1; l++; j = 0; }
      if(l >= undo_action_end[last_undo_action].nline && j/4 >= k) break;
    }//end while
    totalCharsInLine[l] = strlen(lines[l])/4;
    
    while(LINE_IS_LINKED[l]) 
    {
      j = MAX_CHARS_PER_LINE-(strlen(lines[l])/4);
      strncat(lines[l], lines[l+1], j*4);
      char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4);
      strcpy(tmp, lines[l+1]+(j*4));
      strcpy(lines[l+1], tmp);
      if(strlen(lines[l+1])/4 < j) 
      {
	for(i = l+1; i < totalLines-1; i++) 
	{
	  strcpy(lines[i], lines[i+1]);
	  LINE_IS_LINKED[i] = LINE_IS_LINKED[i+1];
	} totalLines--;
	LINE_IS_LINKED[l] = 0;
      }
      free(tmp);
      l++; if(l >= totalLines) break;
    }
    
    l = undo_action_end[last_undo_action].nline;
    i = undo_action_start[last_undo_action].nline;
    last_undo_action--;
    selectedChar = undo_action_start[last_undo_action].nchar;
    totalLines += (l-i);
    //adjust the view
    if((l-i) > 0) selectedLine = l-firstVisLine-1;
    if(selectedLine < 0) 
    {
      firstVisLine = l; selectedLine = 0;
    } else if(selectedLine >= totalVisLines) {
      firstVisLine = l-totalVisLines;
      selectedLine = totalVisLines-1;
    }
    refreshView();
  }//end if
}

/************************************************
 * Redo the last action done. Last action can be:
 * UNDO_ACTION_REPLACE: The user replaced a
 * 			character with INSERT on
 * UNDO_ACTION_INSERT: The user typed regularly
 * UNDO_ACTION_DELETE: The user deleted using
 * 			DEL or BACKSPACE
 * **********************************************/
void editMenu_Redo() 
{
  if(last_undo_action < -1) return;
  if(RECORDING_UNDO_ACTION) finish_undo_action();
  last_undo_action++;
  if(last_undo_action >= total_undo_actions) return;
  if(undo_action[last_undo_action] == UNDO_ACTION_REPLACE) 
  {
    int i = strlen(undo_text[last_undo_action]);
    int j = strlen(undo_text_replace[last_undo_action]);
    int k, l = 0;
    if(i == j) 
    {//if #2
      for(k = undo_action_start[last_undo_action].nchar;
	  k <= undo_action_end[last_undo_action].nchar; k++)
	  {
	  //lines[undo_action_start[last_undo_action].nline][k] =
	//	undo_text_replace[last_undo_action][l++];
	    lines[undo_action_start[last_undo_action].nline][k*4] =
		undo_text_replace[last_undo_action][l*4];
	    lines[undo_action_start[last_undo_action].nline][k*4+1] =
		undo_text_replace[last_undo_action][l*4+1];
	    lines[undo_action_start[last_undo_action].nline][k*4+2] =
		undo_text_replace[last_undo_action][l*4+2];
	    lines[undo_action_start[last_undo_action].nline][k*4+3] =
		undo_text_replace[last_undo_action][l*4+3];
	    l++;
	  }
	  if(k == strlen(lines[undo_action_start[last_undo_action].nline])/4)
	    lines[undo_action_start[last_undo_action].nline][k*4] = '\0';
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////
    } else if(j < i) {
      for(k = undo_action_start[last_undo_action].nchar;
	  k < undo_action_start[last_undo_action].nchar+j; k++)
	  {
	  //lines[undo_action_start[last_undo_action].nline][k] =
	//	undo_text_replace[last_undo_action][l++];
	    lines[undo_action_start[last_undo_action].nline][k*4] =
		undo_text_replace[last_undo_action][l*4];
	    lines[undo_action_start[last_undo_action].nline][k*4+1] =
		undo_text_replace[last_undo_action][l*4+1];
	    lines[undo_action_start[last_undo_action].nline][k*4+2] =
		undo_text_replace[last_undo_action][l*4+2];
	    lines[undo_action_start[last_undo_action].nline][k*4+3] =
		undo_text_replace[last_undo_action][l*4+3];
	    l++;
	  }
      l = k;
      for(k = l; k < (strlen(lines[undo_action_start[last_undo_action].nline])/4)-(i-j); k++)
	  //lines[undo_action_start[last_undo_action].nline][k] =
	    //lines[undo_action_start[last_undo_action].nline][k+i-j];
	  {
	    lines[undo_action_start[last_undo_action].nline][k*4] =
		undo_text_replace[last_undo_action][(k+i-j)*4];
	    lines[undo_action_start[last_undo_action].nline][k*4+1] =
		undo_text_replace[last_undo_action][(k+i-j)*4+1];
	    lines[undo_action_start[last_undo_action].nline][k*4+2] =
		undo_text_replace[last_undo_action][(k+i-j)*4+2];
	    lines[undo_action_start[last_undo_action].nline][k*4+3] =
		undo_text_replace[last_undo_action][(k+i-j)*4+3];
	  }
      lines[undo_action_start[last_undo_action].nline][k*4] = '\0';
      totalCharsInLine[undo_action_start[last_undo_action].nline] =
	  strlen(lines[undo_action_start[last_undo_action].nline]);
      //check to see if the line is linked..
      l = undo_action_start[last_undo_action].nline;
      while(LINE_IS_LINKED[l]) 
      {
	j = MAX_CHARS_PER_LINE-(strlen(lines[l])/4);
	strncat(lines[l], lines[l+1], j*4);
	strcpy(lines[l+1], lines[l+1]+(j*4));
	totalCharsInLine[l] = strlen(lines[l])/4;
	totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	l++; if(l >= totalLines) break;
      }
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////
    } else {
      l = undo_action_end[last_undo_action].nchar;
      int m = (strlen(lines[undo_action_start[last_undo_action].nline])/4)+j-i;
      for(k = m; k > l; k--)
	  //lines[undo_action_start[last_undo_action].nline][k] =
	    //lines[undo_action_start[last_undo_action].nline][k-(j-i)];
      {
	lines[undo_action_start[last_undo_action].nline][k*4] =
	  lines[undo_action_start[last_undo_action].nline][(k-(j-i))*4];
	lines[undo_action_start[last_undo_action].nline][k*4+1] =
	  lines[undo_action_start[last_undo_action].nline][(k-(j-i))*4+1];
	lines[undo_action_start[last_undo_action].nline][k*4+2] =
	  lines[undo_action_start[last_undo_action].nline][(k-(j-i))*4+2];
	lines[undo_action_start[last_undo_action].nline][k*4+3] =
	  lines[undo_action_start[last_undo_action].nline][(k-(j-i))*4+3];
      }
      lines[undo_action_start[last_undo_action].nline][(m+1)*4] = '\0';
      totalCharsInLine[undo_action_start[last_undo_action].nline] =
	  strlen(lines[undo_action_start[last_undo_action].nline])/4;
      l = 0;
      for(k = undo_action_start[last_undo_action].nchar;
	  k < undo_action_start[last_undo_action].nchar+j; k++)
	  {
	  //lines[undo_action_start[last_undo_action].nline][k] =
	//	undo_text_replace[last_undo_action][l++];
	    lines[undo_action_start[last_undo_action].nline][k*4] =
		undo_text_replace[last_undo_action][l*4];
	    lines[undo_action_start[last_undo_action].nline][k*4+1] =
		undo_text_replace[last_undo_action][l*4+1];
	    lines[undo_action_start[last_undo_action].nline][k*4+2] =
		undo_text_replace[last_undo_action][l*4+2];
	    lines[undo_action_start[last_undo_action].nline][k*4+3] =
		undo_text_replace[last_undo_action][l*4+3];
	    l++;
	  }
      //if the line becomes too long, check to see if the line is 
      //linked. If it is, grab characters from the next line and
      //append them here.. continue till we hit a nonlinked line.
      l = undo_action_start[last_undo_action].nline;
      if(totalCharsInLine[l] > MAX_CHARS_PER_LINE) 
      {//if1
	if(LINE_IS_LINKED[l]) 
	{//if2
	  char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4);
	  while(LINE_IS_LINKED[l]) 
	  {
	    strcpy(tmp, lines[l+1]);
	    strcpy(lines[l+1], lines[l]+(MAX_CHARS_PER_LINE*4));
	    lines[l][MAX_CHARS_PER_LINE*4] = '\0';
	    totalCharsInLine[l] = strlen(lines[l])/4;
	    strcat(lines[l+1], tmp);
	    totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	    l++; if(l >= totalLines) break;
	  }//end while
	  //check the last line is not too long
	  if(totalCharsInLine[l]/4 > MAX_CHARS_PER_LINE) 
	  {
	    //make some room
	    for(i = totalLines; i > l+1; i++) 
	    {
	      strcpy(lines[i], lines[i-1]);
	      totalCharsInLine[i] = strlen(lines[i])/4;
	      LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
	    }
	    strcpy(lines[l+1], lines[l]+(MAX_CHARS_PER_LINE*4));
	    lines[l][MAX_CHARS_PER_LINE*4] = '\0';
	    LINE_IS_LINKED[l] = 1;
	    totalCharsInLine[l] = strlen(lines[l])/4;
	    totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	  }
	  free(tmp);
	} else {
	  for(i = totalLines; i > l+1; i--) 
	  {
	    strcpy(lines[i], lines[i-1]);
	    totalCharsInLine[i] = strlen(lines[i])/4;
	    LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
	  } totalLines++;
	  strcpy(lines[l+1], lines[l]+(MAX_CHARS_PER_LINE*4));
	  lines[l][MAX_CHARS_PER_LINE*4] = '\0';
	  totalCharsInLine[l] = strlen(lines[l])/4;
	  totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	  LINE_IS_LINKED[l] = 1;
	}//end if2
      }//end if1
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////
    }//end if #2
    l = undo_action_start[last_undo_action].nline;
    selectedChar = undo_action_start[last_undo_action].nchar;
    selectedLine = l-firstVisLine;
    if(selectedLine < 0) 
    {
      firstVisLine = l; selectedLine = 0;
    } else if(selectedLine >= totalVisLines) {
      firstVisLine = l-totalVisLines;
      selectedLine = totalVisLines-1;
    }
    refreshView();
  } else if(undo_action[last_undo_action] == UNDO_ACTION_DELETE) {
    sel_range_start.nline = undo_action_start[last_undo_action].nline;
    sel_range_end.nline = undo_action_end[last_undo_action].nline;
    sel_range_start.nchar = undo_action_start[last_undo_action].nchar;
    sel_range_end.nchar = undo_action_end[last_undo_action].nchar;
    remove_selected_text(0);
    refreshView();
  } else if(undo_action[last_undo_action] ==  UNDO_ACTION_INSERT) {
    int l, i = undo_action_end[last_undo_action].nline -
	    undo_action_start[last_undo_action].nline;
    if(i)
      for(l = totalLines+i; l > undo_action_end[last_undo_action].nline; l--) {
	strcpy(lines[l], lines[l-i]);
	totalCharsInLine[l] = strlen(lines[l])/4;
	LINE_IS_LINKED[l] = LINE_IS_LINKED[l-i];
      }
    int j = undo_action_start[last_undo_action].nchar;
    int k = undo_action_end[last_undo_action].nchar;
    
    totalLines += i;
    l = undo_action_start[last_undo_action].nline;
    //save the rest of the line to reattach it later
    char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4);
    strcpy(tmp, "");
    strcpy(tmp, lines[l]+(j*4));
    int ltmp = LINE_IS_LINKED[l];
    i = 0;
    while(l <= undo_action_end[last_undo_action].nline) 
    {
      //if(j >= totalCharsInLine[l]) { l++; j = 0; }
      if(undo_text[last_undo_action][i] == '\n') 
      { LINE_IS_LINKED[l] = 0; lines[l][j] = '\0'; l++; j = 0; i+=4; }
      if(j > MAX_CHARS_PER_LINE*4) { LINE_IS_LINKED[l] = 1; l++; j = 0; }
      if(l >= undo_action_end[last_undo_action].nline && j >= k) break;
      lines[l][j*4] = undo_text[last_undo_action][i];
      lines[l][j*4+1] = undo_text[last_undo_action][i+1];
      lines[l][j*4+2] = undo_text[last_undo_action][i+2];
      lines[l][j*4+3] = undo_text[last_undo_action][i+3];
      i+=4; j++;
    }//end while
    lines[l][j*4] = '\0';
    int ptmp = l;
    //reattach the rest of line we saved earlier
    if(strlen(tmp) != 0) 
    {
      k = MAX_CHARS_PER_LINE-(strlen(lines[l])/4);
      strncat(lines[l], tmp, k*4);
      if(strlen(tmp)/4 > k) {
	for(i = totalLines; i > l+1; i--) 
	{
	  strcpy(lines[i], lines[i-1]);
	  totalCharsInLine[i] = strlen(lines[i])/4;
	  LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
	} totalLines++;
	for(i = 0; i < (strlen(tmp)/4)-k; i++)
	{
	  tmp[i*4] = tmp[(i+k)*4];
	  tmp[i*4+1] = tmp[(i+k)*4+1];
	  tmp[i*4+2] = tmp[(i+k)*4+2];
	  tmp[i*4+3] = tmp[(i+k)*4+3];
	}
	tmp[i*4] = '\0';
	strcpy(lines[l+1], tmp);
	totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	LINE_IS_LINKED[l] = 1;
	ptmp++;
      }
      //strcpy(lines[l+1], lines[l]+MAX_CHARS_PER_LINE);
      //lines[l][MAX_CHARS_PER_LINE] = '\0';
      //ptmp++;
    }
    totalCharsInLine[l] = strlen(lines[l])/4;
    //if the first line was linked, relink
    while(ltmp) 
    {
      k = MAX_CHARS_PER_LINE-(strlen(lines[ptmp])/4);
      strncat(lines[ptmp], lines[ptmp+1], k*4);
      //if line is short, remove it
      if(strlen(lines[ptmp+1])/4 < k) 
      {
	for(i = ptmp+1; i < totalLines-1; i++) 
	{
	  strcpy(lines[i], lines[i+1]);
	  totalCharsInLine[i] = strlen(lines[i])/4;
	  LINE_IS_LINKED[i] = LINE_IS_LINKED[i+1];
	} totalLines--;
	LINE_IS_LINKED[ptmp] = 0; break;
      }
      ltmp = LINE_IS_LINKED[++ptmp];
      for(i = k; i < strlen(lines[ptmp])/4; i++)
      {
	lines[ptmp][i*4] = lines[ptmp][(i+1)*4];
	lines[ptmp][i*4+1] = lines[ptmp][(i+1)*4+1];
	lines[ptmp][i*4+2] = lines[ptmp][(i+1)*4+2];
	lines[ptmp][i*4+3] = lines[ptmp][(i+1)*4+3];
      }
      totalCharsInLine[ptmp] = strlen(lines[ptmp])/4;
    }
    free(tmp);
    selectedChar = j;
    //adjust the view
    ptmp = l;
    selectedLine = ptmp-firstVisLine;
    if(selectedLine < 0) 
    {
      firstVisLine = ptmp; selectedLine = 0;
    } else if(selectedLine >= totalVisLines) {
      firstVisLine = ptmp-totalVisLines;
      selectedLine = totalVisLines-1;
    }
    refreshView();
  }//end if
}

void begin_undo_action(undoActionType utype) 
{
  if(last_undo_action >= MAX_UNDO_ACTIONS-1) 
  {
    //the the undo queue is full, move all members down one
    //place to make room for a new undo action.
    int i;
    for(i = 0; i < MAX_UNDO_ACTIONS-1; i++) 
    {
      undo_action[i] = undo_action[i+1];
      strcpy(undo_text[i], undo_text[i+1]);
      strcpy(undo_text_replace[i], undo_text_replace[i+1]);
      undo_action_start[i] = undo_action_start[i+1];
      undo_action_end[i] = undo_action_end[i+1];
    } last_undo_action = MAX_UNDO_ACTIONS-2;
  }
  last_undo_action++;
  total_undo_actions = last_undo_action+1;
  undo_action_start[last_undo_action].nline = firstVisLine+selectedLine;
  undo_action_start[last_undo_action].nchar = selectedChar;
  strcpy(undo_text[last_undo_action], "\0");
  strcpy(undo_text_replace[last_undo_action], "\0");
  //undo_text[last_undo_action][0] = ch;
  //undo_text[last_undo_action][1] = '\0';
  undo_action[last_undo_action] = utype;
  RECORDING_UNDO_ACTION = 1;
}

void finish_undo_action() 
{
  int tmp;
  if(undo_action_end[last_undo_action].nline < undo_action_start[last_undo_action].nline) 
  {
    tmp = undo_action_end[last_undo_action].nline;
    undo_action_end[last_undo_action].nline = undo_action_start[last_undo_action].nline;
    undo_action_start[last_undo_action].nline = tmp;
  } 
  else if(undo_action_end[last_undo_action].nline == undo_action_start[last_undo_action].nline) 
  {
    if(undo_action_end[last_undo_action].nchar < undo_action_start[last_undo_action].nchar) 
    {
      tmp = undo_action_end[last_undo_action].nchar;
      undo_action_end[last_undo_action].nchar = undo_action_start[last_undo_action].nchar;
      undo_action_start[last_undo_action].nchar = tmp;
    }
  }
  RECORDING_UNDO_ACTION = 0;
}

void add_to_undo_action(char *ch) 
{
  int i = strlen(undo_text[last_undo_action]);
    if(undo_action[last_undo_action] == UNDO_ACTION_DELETE) 
    {
     //make sure deleting on one line
     if(undo_action_start[last_undo_action].nline == 
	 undo_action_end[last_undo_action].nline)
      if(((undo_action_end[last_undo_action].nline == firstVisLine+selectedLine)
	&& (undo_action_end[last_undo_action].nchar == selectedChar+1))
	|| (strlen(undo_text[last_undo_action]) == 0)) 
      {
	for(i = strlen(undo_text[last_undo_action])+3; i > 3; i--)
	  undo_text[last_undo_action][i] = undo_text[last_undo_action][i-4];
	undo_text[last_undo_action][0] = ch[0];
	undo_text[last_undo_action][1] = ch[1];
	undo_text[last_undo_action][2] = ch[2];
	undo_text[last_undo_action][3] = ch[3];
	undo_action_end[last_undo_action].nline = firstVisLine+selectedLine;
	undo_action_end[last_undo_action].nchar = selectedChar;
	return;
      } 
      else if((undo_action_end[last_undo_action].nline == firstVisLine+selectedLine)
	&& (undo_action_end[last_undo_action].nchar == selectedChar-1)) 
      {
	//undo_text[last_undo_action][i] = ch;
	undo_text[last_undo_action][i] = ch[0];
	undo_text[last_undo_action][i+1] = ch[1];
	undo_text[last_undo_action][i+2] = ch[2];
	undo_text[last_undo_action][i+3] = ch[3];
	undo_text[last_undo_action][i+4] = '\0';
	undo_action_end[last_undo_action].nline = firstVisLine+selectedLine;
	undo_action_end[last_undo_action].nchar = selectedChar;
      } 
      else 
      {
	finish_undo_action();
	begin_undo_action(UNDO_ACTION_DELETE);
      }
      //deleting multiple lines?? carry on..
    }
      //undo_text[last_undo_action][i] = ch;
      //undo_text[last_undo_action][i+1] = '\0';
      undo_text[last_undo_action][i] = ch[0];
      undo_text[last_undo_action][i+1] = ch[1];
      undo_text[last_undo_action][i+2] = ch[2];
      undo_text[last_undo_action][i+3] = ch[3];
      undo_text[last_undo_action][i+4] = '\0';
      undo_action_end[last_undo_action].nline = firstVisLine+selectedLine;
      undo_action_end[last_undo_action].nchar = selectedChar;
}//end function



/*****************************************
 * Finds a string text in the file.
 * ***************************************/
void editMenu_Find() 
{
  inputBox("Enter text to find:  ", " Find ");
  char *f = (char *)malloc(strlen(input));
  strcpy(f, input);
  if(!strlen(f)) 
  {
    refreshView();
    return;
  }//end if
  
  int i, k = 0;
  char *j, *l;
  total_find_results = 0;
  for(i = 0; i < totalLines; i++) 
  {
    j = strstr(lines[i], f);
    while(j) 
    { 
      find_result_pos[k].nline = i; 
      find_result_pos[k++].nchar = (j-lines[i])/4;
      total_find_results++;
      l = j+strlen(f);
      j = strstr(l, f);
    }//end while
  }//end for
  
  if(!total_find_results) 
  {
    msgBox("No matches were found.", OK, INFO);
    refreshView();
    return;
  }
  
  //infinite loop to get user input
  i = 0;
  while(1) 
  {
    if(find_result_pos[i].nline-firstVisLine > totalVisLines) 
    {
      firstVisLine = find_result_pos[i].nline-totalVisLines;
      selectedLine = totalVisLines;
    } 
    else 
    {
      //firstVisLine = totalLines-totalVisLines;
      selectedLine = find_result_pos[i].nline;
    }
    selectedChar = find_result_pos[i].nchar;
    refreshView();
    setScreenColors(FG_COLOR[COLOR_STATUS_BAR], BG_COLOR[COLOR_STATUS_BAR]);
    printf("\e[%d;1HFind(%d/%d): [Up] Prev [Down] Next [ESC] Cancel",
	   SCREEN_H, i+1, total_find_results);
    fprintf(stdout, "\e[%d;%dH", selectedLine+3, selectedChar+2);
    fflush(stdout);
    char *c = (char *)malloc(5);
get_key:
    c = getKey();
    switch(c[0]) 
    {
      case(UP_KEY):
	if(i <= 0) i = total_find_results-1;
	else i--;
	break;
      case(ENTER_KEY):
      case(SPACE_KEY):
      case(DOWN_KEY):
	if(i >= total_find_results-1) i = 0;
	else i++;
	break;
      case(ESC_KEY):
	refreshView();
	return;
	break;
      default:
	goto get_key;
	break;
    }//end switch
  }//end while
}


/*****************************************
 * Replaces Find text with Replace text.
 * ***************************************/
void editMenu_Replace() 
{
  inputBox("Enter text to find:  ", " Find ");
  char *f = (char *)malloc(strlen(input));
  strcpy(f, input);
  if(!strlen(f)) 
  {
    refreshView();
    return;
  }//end if
  inputBox("Enter replacement text: ", " Replace ");
  char *r = (char *)malloc(strlen(input));
  strcpy(r, input);
  
  int i, k = 0;
  char *j, *l;
  total_find_results = 0;
  for(i = 0; i < totalLines; i++) 
  {
    j = strstr(lines[i], f);
    while(j) 
    { 
      find_result_pos[k].nline = i; 
      find_result_pos[k++].nchar = (j-lines[i])/4;
      total_find_results++;
      l = j+strlen(f);
      j = strstr(l, f);
    }//end while
  }//end for
  
  if(!total_find_results) 
  {
    msgBox("No matches were found.", OK, INFO);
    refreshView();
    return;
  }
  
  //infinite loop to get user input
  i = 0;
  while(1) 
  {
    /*if(totalLines-find_result_pos[i].nline > totalVisLines) {
      firstVisLine = find_result_pos[i].nline;
      selectedLine = 0;
    } else {
      firstVisLine = totalLines-totalVisLines;
      selectedLine = find_result_pos[i].nline-firstVisLine;
    }*/
    if(find_result_pos[i].nline-firstVisLine > totalVisLines) 
    {
      firstVisLine = find_result_pos[i].nline-totalVisLines;
      selectedLine = totalVisLines;
    } 
    else 
    {
      //firstVisLine = totalLines-totalVisLines;
      selectedLine = find_result_pos[i].nline;
    }
    selectedChar = find_result_pos[i].nchar;
    refreshView();
    setScreenColors(FG_COLOR[COLOR_STATUS_BAR], BG_COLOR[COLOR_STATUS_BAR]);
    printf("\e[%d;1HFind(%d/%d): [ENTER] Replace [A] Replace All [ESC] Cancel",
	   SCREEN_H, i+1, total_find_results);
    fprintf(stdout, "\e[%d;%dH", selectedLine+3, selectedChar+2);
    fflush(stdout);
    char *c = (char *)malloc(5);
get_key:
    c = getKey();
    switch(c[0]) 
    {
      case(UP_KEY):
	if(i <= 0) i = total_find_results-1;
	else i--;
	break;
      case(DOWN_KEY):
	if(i >= total_find_results-1) i = 0;
	else i++;
	break;
      case(ESC_KEY):
	refreshView();
	return;
	break;
      case(SPACE_KEY):
      case(ENTER_KEY):
	_replace(i, f, r);
	if(i >= total_find_results) i--;
	if(total_find_results <= 0) { refreshView(); return; }
	break;
      case('a'):
	_replace(-1, f, r);
	total_find_results = 0;
	refreshView();
	return;
	break;
      default:
	goto get_key;
	break;
    }//end switch
  }//end while
}

/*******************************************
 * Function is called by minoMenu_Replace()
 * to replace find result number 'pos' with
 * the replacement text.
 * *****************************************/
void _replace(int pos, char *f, char *r) 
{
  //pass position to replace in find_result_pos[] array,
  //or -1 to replace all find results.
  int i = strlen(f);
  int j = strlen(r);
  int k, l, m, n; k = 0;
  
  if(pos >= 0) 
  {//if #1
    k = find_result_pos[pos].nchar;
    l = find_result_pos[pos].nline;
    n = 0;
    if(RECORDING_UNDO_ACTION) finish_undo_action();
    begin_undo_action(UNDO_ACTION_REPLACE);
    for(m = 0; m < i; m+=4)
      { add_to_undo_action(f+m); selectedChar++; }
    //selectedChar += i;
    strcpy(undo_text_replace[last_undo_action], r);
    finish_undo_action();
    
    if(i == j) {//if #2
      //find & replace of same length
      for(m = k*4; m < k*4+i; m++)
	lines[l][m] = r[n++];
    } else if(i > j) {
      //find is longer than replace
      for(m = k*4; m < k*4+j; m++)
	lines[l][m] = r[n++];
      n = m;
      for(m = n; m < totalCharsInLine[l]*4-j; m++)
	lines[l][m] = lines[l][m+i-j];
      lines[l][m] = '\0';
      totalCharsInLine[l] = strlen(lines[l])/4;
    } else {
      //replace is longer than find
      n = j-i;
      //make some room first
      for(m = totalCharsInLine[l]*4+n-1; m > k*4+j-1; m--)
	lines[l][m] = lines[l][m-n];
      lines[l][totalCharsInLine[l]*4+n] = '\0';
      //then copy replace on top of find
      n = 0;
      for(m = k*4; m < k*4+j; m++)
	lines[l][m] = r[n++];
      totalCharsInLine[l] = strlen(lines[l])/4;
    }//end if #2
    //if there are other find results in the same line, they will need
    //to be shifted. The degree of shift depends on the difference between
    //the length of the find and replace strings.
    k = j-i;
    //update the find_result_pos[] array by removing the replaced item
    for(m = pos; m < total_find_results-1; m++) 
    {
      find_result_pos[m].nline = find_result_pos[m+1].nline;
      find_result_pos[m].nchar = find_result_pos[m+1].nchar;
      if(find_result_pos[m].nline == l) 
      {//correct result position
	find_result_pos[m].nchar += k;
	//undo_action_start[last_undo_action].nchar += k;
      }
    }//end for
    total_find_results--;
    selectedChar += k;
    FILE_STATE = MODIFIED;
    //check to see if the line is becoming too long. If so,
    //append it to next line (if already linked to), or make
    //a new empty line and dump extra chars into it.
    if(totalCharsInLine[l] > MAX_CHARS_PER_LINE) 
    {//if1
      if(LINE_IS_LINKED[l]) 
      {//if2
	char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4);
	while(LINE_IS_LINKED[l]) 
	{
	  strcpy(tmp, lines[l+1]);
	  strcpy(lines[l+1], lines[l]+(MAX_CHARS_PER_LINE*4));
	  lines[l][MAX_CHARS_PER_LINE*4] = '\0';
	  strcat(lines[l+1], tmp);
	  totalCharsInLine[l] = strlen(lines[l])/4;
	  totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	  l++;
	}//end while
	free(tmp);
      } 
      else 
      {
	for(i = totalLines; i > l+1; i--) 
	{
	  strcpy(lines[i], lines[i-1]);
	  totalCharsInLine[i] = strlen(lines[i])/4;
	  LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
	}
	strcpy(lines[l+1], lines[l]+(MAX_CHARS_PER_LINE*4));
	lines[l][MAX_CHARS_PER_LINE*4] = '\0';
	totalCharsInLine[l] = strlen(lines[l])/4;
	totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	LINE_IS_LINKED[l] = 1;
	LINE_IS_LINKED[l+1] = 0;
	totalLines++;
	//if there are any search results beyond this point,
	//they will need shifting down.
	for(m = pos; m < total_find_results; m++) 
	{
	  if(find_result_pos[m].nline > l) //correct result position
	    find_result_pos[m].nline++;
	}//end for
      }//end if2
      return;
    }//end if1
    //check to see if the line is linked to next line.
    //if so, grab chars from next line and append them here.
    //continue till we hit a non linked line.
    while(LINE_IS_LINKED[l]) 
    {
      j = MAX_CHARS_PER_LINE-(strlen(lines[l])/4);
      if(j == 0) break;
      strncat(lines[l], lines[l+1], j*4);
      strcpy(lines[l+1], lines[l+1]+(j*4));
      totalCharsInLine[l] = strlen(lines[l])/4;
      totalCharsInLine[l+1] = strlen(lines[l+1])/4;
      if(strlen(lines[l+1])/4 < j) 
      {//remove the line as we copied all of it
	for(i = l+1; i < totalLines-1; i++) 
	{
	  strcpy(lines[i], lines[i+1]);
	  totalCharsInLine[i] = strlen(lines[i])/4;
	  LINE_IS_LINKED[i] = LINE_IS_LINKED[i+1];
	} totalLines--;
	//and adjust any search results beyond this point.
	for(m = pos; m < total_find_results; m++)
	  if(find_result_pos[m].nline > l) //correct result position
	    find_result_pos[m].nline--;
      }
      l++; if(l >= totalLines) break;
    }//end while
  ////////////////////////////////////////////////////
  ////////////////////////////////////////////////////
  ////////////////////////////////////////////////////
  } else {	//-1 means replace all
    if(RECORDING_UNDO_ACTION) finish_undo_action();
    int carry = 0;
    for(pos = 0; pos < total_find_results; pos++) 
    {
      i = strlen(f);
      j = strlen(r);
      //for each item, add an entry to the undo queue
      //if(totalLines-find_result_pos[pos].nline > totalVisLines) {
	firstVisLine = find_result_pos[pos].nline;
	selectedLine = 0;
      //} else {
	//firstVisLine = totalLines-totalVisLines;
	//selectedLine = find_result_pos[pos].nline-firstVisLine;
      //}
      selectedChar = find_result_pos[pos].nchar;
      begin_undo_action(UNDO_ACTION_REPLACE);
      for(m = 0; m < i; m+=4)
      { add_to_undo_action(f+m); selectedChar++; }
      selectedChar += carry;
      strcpy(undo_text_replace[last_undo_action], r);
      finish_undo_action();
      //--finished recording undo action

      k = find_result_pos[pos].nchar;
      l = find_result_pos[pos].nline;
      n = 0;
      if(i == j) {//if #2
	//find & replace of same length
	for(m = k*4; m < k*4+i; m++)
	  lines[l][m] = r[n++];
      } else if(i > j) {
	//find is longer than replace
	for(m = k*4; m < k*4+j; m++)
	  lines[l][m] = r[n++];
	n = m;
	for(m = n; m < totalCharsInLine[l]*4-j; m++)
	  lines[l][m] = lines[l][m+i-j];
	lines[l][m] = '\0';
	totalCharsInLine[l] = strlen(lines[l])/4;
      } else {
	//replace is longer than find
	n = j-i;
	//make some room first
	for(m = totalCharsInLine[l]*4+n-1; m > k*4+j-1; m--)
	  lines[l][m] = lines[l][m-n];
	lines[l][totalCharsInLine[l]*4+n] = '\0';
	//then copy replace on top of find
	n = 0;
	for(m = k*4; m < k*4+j; m++)
	  lines[l][m] = r[n++];
	totalCharsInLine[l] = strlen(lines[l])/4;
      }//end if #2
      
      //if there are other find results in the same line, they will need
      //to be shifted. The degree of shift depends on the difference between
      //the length of the find and replace strings.
      k = j-i; carry = 0;
      //update the find_result_pos[] array by removing the replaced item
      for(m = pos+1; m < total_find_results; m++) 
      {//for2
	if(find_result_pos[m].nline == l) {//correct result position
	  find_result_pos[m].nchar += k;
	  carry = k;
	  //undo_action_start[last_undo_action].nchar += k;
	}
      }//end for2
      
      //check to see if the line is becoming too long. If so,
      //append it to next line (if already linked to), or make
      //a new empty line and dump extra chars into it.
      if(totalCharsInLine[l] > MAX_CHARS_PER_LINE) 
      {//if1
	if(LINE_IS_LINKED[l]) 
	{//if2
	  char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4);
	  while(LINE_IS_LINKED[l]) 
	  {
	    strcpy(tmp, lines[l+1]);
	    strcpy(lines[l+1], lines[l]+(MAX_CHARS_PER_LINE*4));
	    lines[l][MAX_CHARS_PER_LINE*4] = '\0';
	    strcat(lines[l+1], tmp);
	    totalCharsInLine[l] = strlen(lines[l])/4;
	    totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	    l++;
	  }//end while
	  free(tmp);
	} 
	else 
	{
	  for(i = totalLines; i > l+1; i--) 
	  {
	    strcpy(lines[i], lines[i-1]);
	    totalCharsInLine[i] = strlen(lines[i])/4;
	    LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
	  } totalLines++;
	  strcpy(lines[l+1], lines[l]+(MAX_CHARS_PER_LINE*4));
	  lines[l][MAX_CHARS_PER_LINE*4] = '\0';
	  totalCharsInLine[l] = strlen(lines[l])/4;
	  totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	  LINE_IS_LINKED[l] = 1;
	  LINE_IS_LINKED[l+1] = 0;
	  //if there are any search results beyond this point,
	  //they will need shifting down.
	  for(m = pos+1; m < total_find_results; m++) 
	  {
	    if(find_result_pos[m].nline > l) //correct result position
	      find_result_pos[m].nline++;
	  }//end for
	}//end if2
	continue;
      }//end if1
      //check to see if the line is linked to next line.
      //if so, grab chars from next line and append them here.
      //continue till we hit a non linked line.
      while(LINE_IS_LINKED[l]) 
      {
	j = (MAX_CHARS_PER_LINE*4)-strlen(lines[l]);
	if(j == 0) break;
	strncat(lines[l], lines[l+1], j);
	strcpy(lines[l+1], lines[l+1]+j);
	totalCharsInLine[l] = strlen(lines[l])/4;
	totalCharsInLine[l+1] = strlen(lines[l+1])/4;
	if(strlen(lines[l+1]) < j) {//remove the line as we copied all of it
	  for(i = l+1; i < totalLines-1; i++) 
	  {
	    strcpy(lines[i], lines[i+1]);
	    totalCharsInLine[i] = strlen(lines[i])/4;
	    LINE_IS_LINKED[i] = LINE_IS_LINKED[i+1];
	  } totalLines--;
	  //and adjust any search results beyond this point.
	  for(m = pos+1; m < total_find_results; m++)
	    if(find_result_pos[m].nline > l) //correct result position
	      find_result_pos[m].nline--;
	}
	l++; if(l >= totalLines) break;
      }//end while
      
    }//end for1
    FILE_STATE = MODIFIED;
    selectedChar += k; pos--;
    /*if(totalLines-find_result_pos[pos].nline > totalVisLines) {
	firstVisLine = find_result_pos[pos].nline;
	selectedLine = 0;
    } else {
	firstVisLine = totalLines-totalVisLines;
	selectedLine = find_result_pos[pos].nline-firstVisLine;
    }*/
    if(find_result_pos[pos].nline-firstVisLine > totalVisLines) 
    {
      firstVisLine = find_result_pos[pos].nline-totalVisLines;
      selectedLine = totalVisLines;
    } 
    else 
    {
      //firstVisLine = totalLines-totalVisLines;
      selectedLine = find_result_pos[pos].nline;
    }
  }//end if #1
}

void checkAllTabs() 
{
  int i;
  for(i = 0; i < totalLines; i++)
    checkTabsInLine(i);
}

void checkTabsInLine(int pos) 
{
  int i, j, k, l;
  int carry = 0; 
  char *tmp = (char *) malloc(MAX_CHARS_PER_LINE*4);
  //here comes the real stuff
  for(l = 0; l < strlen(lines[pos]); l+=4)
    if(lines[pos][l] == '\t') 
    {
      j = TAB_CHARS-(((l/4)+carry)%TAB_CHARS);
      j = 0 ? 8 : j;
      carry += (j-1);
      
      int k = (strlen(lines[pos])/4)+carry;
      char *t = (char *) malloc(MAX_CHARS_PER_LINE*4);
      strcpy(t, lines[pos]);
      
      if((strlen(lines[pos])/4)+carry > MAX_CHARS_PER_LINE) 
      {
	if(LINE_IS_LINKED[pos]) 
	{
	  int j2;
	  while(LINE_IS_LINKED[pos]) 
	  {
	    //j = MAX_CHARS_PER_LINE-strlen(lines[pos]);
	    //j2 = (strlen(lines[pos])+(j-1);
	    j2 = MAX_CHARS_PER_LINE-(carry);
	    strcpy(tmp, lines[pos+1]);
	    strcpy(lines[pos+1], lines[pos]+(j2*4));
	    lines[pos][j2*4] = '\0';
	    lines[pos][j2*4+1] = '\0';
	    lines[pos][j2*4+2] = '\0';
	    lines[pos][j2*4+3] = '\0';
	    strcat(lines[pos+1], tmp);
	    pos++; if(pos >= totalLines) break;
	  }//end while
	  if(strlen(lines[pos])/4 > MAX_CHARS_PER_LINE)
	  {
	    for(i = totalLines; i > pos+1; i--) 
	    {
	      strcpy(lines[i], lines[i-1]);
	      //totalCharsInLine[i] = strlen(lines[i]);
	      LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
	    } totalLines++;
	    strcpy(lines[pos+1], lines[pos]+(j2*4));
	    LINE_IS_LINKED[pos] = 1;
	    LINE_IS_LINKED[pos+1] = 0;
	    lines[pos][j2*4] = '\0';
	    lines[pos][j2*4+1] = '\0';
	    lines[pos][j2*4+2] = '\0';
	    lines[pos][j2*4+3] = '\0';
	    //totalCharsInLine[pos] = strlen(lines[pos]);
	  }
	} 
	else 
	{//line is not linked, create a new line
	  for(i = totalLines; i > pos+1; i--) 
	  {
	    strcpy(lines[i], lines[i-1]);
	    //totalCharsInLine[i] = strlen(lines[i]);
	    LINE_IS_LINKED[i] = LINE_IS_LINKED[i-1];
	  } totalLines++;
	  int j2 = MAX_CHARS_PER_LINE-(carry);
	  //strlen(lines[pos])-(j-1);
	  strcpy(lines[pos+1], lines[pos]+(j2*4));
	  LINE_IS_LINKED[pos] = 1;
	  LINE_IS_LINKED[pos+1] = 0;
	  lines[pos][j2*4] = '\0';
	  lines[pos][j2*4+1] = '\0';
	  lines[pos][j2*4+2] = '\0';
	  lines[pos][j2*4+3] = '\0';
	  //totalCharsInLine[pos] = strlen(lines[pos]);
	}
      }
    }
    
    for(i = 0; i < totalLines; i++) 
    {
      totalCharsInLine[i] = 0;
      int carry = 0;
      for(j = 0; j < strlen(lines[i]); j+=4)
	if(lines[i][j] == '\t') {
	  k = TAB_CHARS-(((j/4)+carry)%TAB_CHARS); k=0?TAB_CHARS:k;
	  totalCharsInLine[i] += k; carry += (k-1);
	} else totalCharsInLine[i]++;
    }
    //refreshView();
  //}
  free(tmp);
  return;
}//end checkTabsInLine()
