//=======================================================================
//	vedcnv.cpp:	Source for vedTextEditor class
//=======================================================================

#include <v/vnotice.h>
#ifdef VIDE
#define VCmdWindow videCmdWindow
#include "videapp.h"
#include "vedcnv.h"
#include "videcmdw.h"
#else
#define VCmdWindow vedCmdWindow
#include "vedapp.h"
#include "vedcnv.h"
#include "vedcmdw.h"
#endif

    const int maxBuff = 300;

//===================>>> vedTextEditor::vedTextEditor <<<====================
  vedTextEditor::vedTextEditor(VCmdWindow* parent) : 
      vTextEditor((vCmdWindow*)parent,1)
  {
  }

//===================>>> vedTextEditor::~vedTextEditor <<<====================
  vedTextEditor::~vedTextEditor()
  {
  }

#define isSpace(x) (x == ' ' || x == '\t')

#define isOp(x) (x=='+' || x=='-' || x=='*' || x=='/' || x=='<' || x=='>' \
	|| x=='?' || x==':' || x==';' || x=='!' || x=='%' || x=='^' || x=='&' \
        || x=='\\' || x=='|' || x == '=' || x==',' || x=='\'' || x=='\"' \
        || x==')' || x=='(' || x=='[' || x==']' || x=='{' || x=='}')


// ======================>>> vTextEditor::paintLine <<<=====================
  void vedTextEditor::paintLine(char* linout, int lineStart,
        int hiStart, int hiLast, long lineNum)
  {
    // paint a line.
    // linout: the line to output with tabs converted to spaces, etc.
    // lineStart: where to begin printing the line (for hoiz. scrolling)
    // hiStart, hiLast: reverse text attribute
    // lineNum: the real line number in the buffer this is.
    // This version overrides the original to handle syntax highlighting

    ChrAttr attrs[MAX_LINE+1];	// for attributes
    int wasComment = 0;

    int linlen = strlen(linout);
    if (linlen <= 0)             // only draw if there!
        return;

    for (int ix = 0 ; ix <= MAX_LINE ; ++ix)	// assume normal
        attrs[ix] = ChNormal;

    // Parse the line for syntax

    if (GetFileType() == CPP)			// if a C file, parse
        wasComment = parseC(linout,attrs,lineNum);
    else if (GetFileType() == gccError)
      {
        int ig = 0;
        while (isSpace(linout[ig]))
          ++ig;
        if (linout[ig] == '>')
          {
            while (linout[ig])
                attrs[ig++] = ChBlue;
          }
        else if (linout[ig] == '!')
          {
            while (linout[ig])
                attrs[ig++] = ChRed;
          }
      }

    // Now fill in highlight attributes
    for (int ih = 0 ; linout[ih] != 0 ; ++ih)
      {
        if (ih >= hiStart && ih < hiLast)
            attrs[ih] = ChHighlight;		// override syntax colors
      }


    for (int ixx = lineStart ; linout[ixx] != 0 ; ++ixx)
	DrawChar(linout[ixx],attrs[ixx]);

  }

#ifdef VIDE
//===================>>> vedTextEditor::TextMouseDown <<<====================
  void vedTextEditor::TextMouseDown(int row, int col, int button)
  {
    int btn = (GetFileType() == gccError) ? 1 : button;

    vTextEditor::TextMouseDown(row, col, btn);	// translate to left
  }

//===================>>> vedTextEditor::TextMouseUP <<<====================
  void vedTextEditor::TextMouseUp(int row, int col, int button)
  {
    int btn = (GetFileType() == gccError) ? 1 : button;
    vTextEditor::TextMouseUp(row, col, btn);
    if (button == 3 && GetFileType() == gccError)  // open error file
      {
        ((VCmdWindow*)_parent)->GotoErrorLine();
      }
  }
#endif


//===================>>> vedTextEditor::parseC <<<====================
  int vedTextEditor::parseC(char* linout, ChrAttr* attrs, long lineNum)
  {

    int ix = 0;
    int wasComment = 0;
    char token[MAX_LINE+1];

    for (ix = 0 ; linout[ix] != 0 ; ++ix)
        if (!isSpace(linout[ix]))
            break;			// skip leading spaces

    while (linout[ix] != 0)
      {
        // gather a token
        int iy;
        for (iy = ix ; linout[iy] != 0 ; ++iy)
          {
            if (isOp(linout[iy]) || isSpace(linout[iy]) )
                break;
          }
        // token goes from ix to iy
        int from = ix;
        if (ix == iy)
            ++iy;		// single char tokens

        char *tp;
        for (tp = token ; from < iy ; ++from)
          *tp++ = linout[from];
        *tp = 0;
        // OK, now highlight the token appropriately
        if (isOp(*token))
          {
            if (*token == '"')
              {
                // A String...
                int ij;
                for (ij = ix ; linout[ij] ; ++ij)
                  {
                    attrs[ij] = ChRed;
                    if (linout[ij] == '\\')
                      {
                        attrs[ij+1] = ChRed;
                        ++ij;
                      }
                    else if (linout[ij] == '"' && ij != ix)
                        break;
                  }
                iy = ij+1;
              }
            else if (*token == '/' && linout[ix+1] == '/')
              {
                // A comment...
                int ij;
                for (ij = ix ; linout[ij] ; ++ij)
                    attrs[ij] = ChGreen | ChDimColor;
                iy = ij;
                wasComment = 1;
              }
            else if (*token == '/' && linout[ix+1] == '*')
              {
                /* A comment... */
                int ij;
                for (ij = ix ; linout[ij] ; ++ij)
                  {
                    attrs[ij] = ChYellow | ChDimColor;
                    if (linout[ij] =='/' && linout[ij-1] == '*') // "*/"
                        break;
                  }
                wasComment = 1;
                if (linout[ij] == 0)
                    break;
                else
                    iy = ij+1;
              }
            else if (*token == '*' && linout[ix+1] == '/')
              {
                /* A comment... */
                int ij;
                for (ij = 0 ; linout[ij] && ij <= ix+1 ; ++ij)
                  {
                    attrs[ij] = ChYellow | ChDimColor;
                    if (linout[ij] =='/' && linout[ij-1] == '*')
                        break;
                  }
                wasComment = 1;
                if (linout[ij] == 0)
                    break;
                else
                    iy = ij+1;
              }
            else
                attrs[ix] |= ChBlue | ChDimColor;
          }
        else if (*token == '#')
          {
            for (int ij = ix ; ij < iy ; ++ij)
                attrs[ij] |= ChCyan | ChDimColor;
          }
        else if (*token >= '0' && *token <= '9')
          {
            for (int ij = ix ; ij < iy ; ++ij)
                attrs[ij] |= ChRed;
          }
        else if (isKeyWord(token))
          {
            for (int ij = ix ; ij < iy ; ++ij)
                attrs[ij] |= ChBlue;
          }

        ix = iy;
      }
    return wasComment;
  }
//===================>>> vedTextEditor::isKeyWord <<<====================
  int vedTextEditor::isKeyWord(char* token)
  {
    char* keywords[] =
     {
	"FALSE", "NULL", "TRUE",
	"asm", "auto", "bool", "break", 
	"case", "catch", "char", "class", "const", "const_cast", 
	"continue", "default", "delete", "do", "double", 
	"dynamic_cast", "else", "enum", "explicit", "extern", 
	"false", "float", "for", "friend", "goto", "if", 
	"inline", "int", "long", "mutable", "namespace", "new",
	"operator", "private", "protected", "public", "register", 
	"reinterpret_cast", "return", "short", "signed", "sizeof", 
	"static", "static_cast", "struct", "switch", "template", 
	"this", "throw", "true", "try", "typedef", "typeid", 
	"typename", "union", "unsigned", "using", "virtual", "void", 
	"volatile", "wchar_t", "while", ""
     };

     for (int ix = 0 ; *keywords[ix] ; ++ix)
       {
         if (strcmp(token,keywords[ix]) == 0)
             return 1;
       }
     return 0;
  }

//===================>>> vedTextEditor::ChangeLoc <<<====================
  void vedTextEditor::ChangeLoc(long line, int col)
  {
    ((VCmdWindow*)_parent)->ChangeLoc(line,col);
  }

//===================>>> vedTextEditor::ChangeInsMode <<<====================
  void vedTextEditor::ChangeInsMode(int IsInsMode, char* msg)
  {
    ((VCmdWindow*)_parent)->ChangeInsMode(IsInsMode, msg);
  }

//===================>>> vedTextEditor::StatusMessage <<<====================
  void vedTextEditor::StatusMessage(char *msg)
  {
    ((VCmdWindow*)_parent)->StatusMessage(msg);
  }

//===================>>> vedTextEditor::ErrorMsg <<<====================
  void vedTextEditor::ErrorMsg(char *str)
  {
  }

//===================>>> vedTextEditor::ReadFile <<<====================
  int vedTextEditor::ReadFile(char* name, int paintIt)
  {

    char buff[maxBuff+2];

    if (!name || !*name)
	return 0;

    ifstream inFile(name);

    if (!inFile)
	return 0;		// file not there

    resetBuff();		// this buffer is empty

    while (inFile.getline(buff,maxBuff))
      {
	if (!addLine(buff))
	  {
	    vNoticeDialog note(theApp);
	    note.Notice("File too big -- only paritally read.");
	    break;
	  }
      }
    inFile.close();
    displayBuff(1,paintIt);		// Now, display the buffer , don't paint
    return 1;
  }

//===================>>> vedTextEditor::SaveFile <<<====================
  int vedTextEditor::SaveFile(char* name)
  {
    char buff[maxBuff+2];

    char* prefix = "Saved ";

    ofstream ofs(name);
    if (!ofs)
      {
	StatusMessage("Can't save file");
	return 0;
      }

    for (long lx = 1 ; lx <= GetLines() ; ++lx)
      {
	getLine(buff,maxBuff,lx);
	ofs << buff << "\n";
      }

    ofs.close();

    strcpy(buff,prefix);

    int ix;
    for (ix = strlen(prefix) ; ix < 40 && *name != 0 ; ++ix)
	buff[ix] = *name++;
    buff[ix] = 0;
    StatusMessage(buff);

    state.changes = 0;
    return 1;
  }
