/*

Copyright (c) 2009, Chris Malek (chris.malek@cedarhillsgroup.com)
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 Cedar Hills Group Inc. 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 
 HOLDER 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.

http://www.freebsd.org/copyright/freebsd-license.html

*/

/* version 1.0 */


class dataDumper
   property string FileName get set;
   
   method dataDumper(&FileNameIn As string);
   
   method purgeFileContents();
   
   method dump(&val As any);
   method dumpString(&stringToWrite As string);
   method dumpRecord(&rec As Record);
   method dumpArrayOfRecords(&array As array of Record);
   method dumpRowset(&rs As Rowset);
   method dumpRow(&row As Row);
   method dumpArray(&array As array);
   method dumpArrayOfString(&array As array of string);
   method emailDumpFile(&address As string);
   method dumpLevelZero();
   method dumpCurrentRow();
   method dumpQueryString();
   method dumpField(&fldField As Field);
   method whiteSpace(&i As integer);
   method dumpHTTPHeader();
   method dumpRowsetValuesAsCSV(&rs As Rowset, &excludeFieldNames As string);
   property string emailSubject;
   property string emailBody;
   property string output;
   property integer indentLevel;
   property string fileContents get;
private
   instance string &UserFileName;
   instance string &FullFileName;
   method openFile() Returns File;
   instance string &crlf;
   instance string &br;
   instance string &LineBreak;
   
end-class;


set FileName
   /+ &NewValue as String +/
   
   &UserFileName = &NewValue;
   
   Local string &tempFileName, &baseDirectory;
   
   If None(&NewValue) Then
      &tempFileName = RTrim(%OperatorId) | ".txt";
   Else
      &tempFileName = RTrim(LTrim(&NewValue));
   End-If;
   
   
   rem &PSHOME = GetEnv("PS_HOME");
   Local string &serverHome;
   &serverHome = GetEnv("PS_SERVDIR");
   
   &baseDirectory = &serverHome | "/LOGS/";
   &FullFileName = &baseDirectory | &tempFileName;
end-set;

get FileName
   /+ Returns String +/
   Return &UserFileName;
end-get;




method dataDumper
   /+ &FileNameIn as String +/
   &crlf = (Char(13) | Char(10));
   &br = "<br/>";
   
   If None(&FileNameIn) Then
      %This.FileName = RTrim(%OperatorId) | "_debug_file.txt";
   Else
      %This.FileName = &FileNameIn;
   End-If;
   
   %This.purgeFileContents();
   
end-method;

method purgeFileContents
   
   Local File &f;
   
   If FileExists(&FullFileName, %FilePath_Absolute) Then
      &f = GetFile(&FullFileName, "W", %FilePath_Absolute);
      &f.Close();
   End-If;
   
end-method;


method openFile
   /+ Returns File +/
   
   Local File &f;
   
   If FileExists(&FullFileName, %FilePath_Absolute) Then
      &f = GetFile(&FullFileName, "A", %FilePath_Absolute);
   Else
      &f = GetFile(&FullFileName, "W", %FilePath_Absolute);
   End-If;
   
   
   Return &f;
end-method;


method dumpString
   /+ &stringToWrite as String +/
   
   Local File &f;
   Local string &temp;
   &temp = Rept(" ", %This.indentLevel) | &stringToWrite;
   &f = %This.openFile();
   &f.WriteLine(&temp);
   &f.Close();
   
   
   
end-method;


method dumpField
   /+ &fldField as Field +/
   %This.dumpString("");
   %This.dumpString("______DUMP FIELD_____");
   %This.dumpString("   " | "Name      : " | &fldField.Name);
   %This.dumpString("   " | "value      : " | &fldField.Value);
   %This.dumpString("   " | "OriginalValue      : " | &fldField.OriginalValue);
   %This.dumpString("   " | "FormattedValue      : " | &fldField.FormattedValue);
   %This.dumpString("   " | "DisplayOnly      : " | &fldField.DisplayOnly);
   %This.dumpString("   " | "Visible      : " | &fldField.Visible);
   %This.dumpString("   " | "IsInBuf      : " | &fldField.IsInBuf);
   %This.dumpString("   " | "isChanged      : " | &fldField.IsChanged);
   If &fldField.IsEditXlat Then
      %This.dumpString("   " | " LongTranslateValue     : " | &fldField.LongTranslateValue);
   End-If;
   %This.dumpString("");
end-method;

method dumpRecord
   /+ &rec as Record +/
   
   
   %This.dumpString("____DUMP_RECORD_____");
   %This.dumpString(" Record.Name: " | &rec.Name);
   
   
   %This.dumpString(("     record.IsChanged: " | &rec.IsChanged));
   %This.dumpString(("     record.IsDeleted: " | &rec.IsDeleted));
   %This.dump("");
   %This.dumpString(("     " | &rec.Name | " field values "));
   Local integer &i;
   Local Field &fldField;
   Local string &changed;
   Local string &spacer;
   Local integer &numbSpaces = 25;
   
   
   For &i = 1 To &rec.FieldCount
      
      If &rec.GetField(&i).IsInBuf Then
         &fldField = &rec.GetField(&i);
         
         
         &spacer = Rept(" ", (&numbSpaces - Len(&fldField.Name)));
         If &rec.GetField(&i).IsChanged Then
            &changed = "    **CHANGED**  Original Value = " | &fldField.OriginalValue;
         Else
            &changed = "";
            
         End-If;
         If &fldField.IsEditXlat Then
            %This.dumpString(("     " | &fldField.Name | &spacer | " ==> " | &fldField.Value | " - " | &fldField.LongTranslateValue | &changed));
         Else
            %This.dumpString(("     " | &fldField.Name | &spacer | " ==> " | &fldField.Value) | &changed);
         End-If;
         
      End-If /* IN BUFFER */
   End-For;
   
end-method;

method dumpArrayOfRecords
   /+ &array as Array of Record +/
   
   
   Local Record &rec;
   Local integer &arrayCounter;
   If All(&array) Then
      For &arrayCounter = 1 To &array.Len
         &rec = &array [&arrayCounter];
         %This.dumpRecord(&rec);
      End-For;
   End-If;
   
end-method;

method dumpRow
   /+ &row as Row +/
   
   
   %This.dumpString("____DUMPING ROW_____");
   rem    %This.dump(" Recname   : " | &row.REC);
   %This.dump(" RowNumber   : " | &row.RowNumber);
   %This.dump(" IsNew       : " | &row.IsNew);
   %This.dump(" IsDeleted   : " | &row.IsDeleted);
   %This.dump(" IsChanged   : " | &row.IsChanged);
   %This.dump(" Visible     : " | &row.Visible);
   
   Local integer &i;
   Local integer &indentPreseve;
   
   &indentPreseve = %This.indentLevel;
   %This.indentLevel = %This.indentLevel + 4;
   For &i = 1 To &row.RecordCount
      %This.whiteSpace(2);
      %This.dumpRecord(&row.GetRecord(&i));
   End-For;
   %This.dumpString("____ENDING DUMP ROW___");
   
   %This.indentLevel = &indentPreseve;
end-method;



method dumpRowset
   /+ &rs as Rowset +/
   %This.dumpString("______DUMPING ROWSET ____");
   
   %This.dumpString(("  DBRecordName: " | &rs.DBRecordName));
   %This.dumpString(("    Level  ==> " | &rs.Level));
   
   
   Local integer &rowCounter;
   Local integer &indentPreseve;
   
   &indentPreseve = %This.indentLevel;
   %This.indentLevel = %This.indentLevel + 4;
   
   
   For &rowCounter = 1 To &rs.RowCount
      Local Row &rw;
      &rw = &rs.GetRow(&rowCounter);
      %This.dumpRow(&rw);
      %This.whiteSpace(2);
      
   End-For; /* row loop */
   %This.indentLevel = &indentPreseve;
   
end-method;

method dumpArray
   /+ &array as Array of Any +/
   
   %This.dumpString("_____BEGIN ARRAY DUMP_____");
   Local integer &debugi;
   If All(&array) Then
      For &debugi = 1 To &array.Len
         %This.dumpString(&array [&debugi]);
      End-For;
   End-If;
   %This.dumpString("_____END ARRAY DUMP_____");
   
end-method;


method dumpArrayOfString
   /+ &array as Array of String +/
   %This.dumpString("_____BEGIN ARRAY DUMP_____");
   Local integer &debugi;
   If All(&array) Then
      For &debugi = 1 To &array.Len
         %This.dumpString(&array [&debugi]);
      End-For;
   End-If;
   %This.dumpString("_____EMAIL ARRAY DUMP_____");
   
end-method;

method emailDumpFile
   /+ &address as String +/
   
   Local string &tmpEmail;
   
   If All(&address) Then
      &tmpEmail = &address;
      Local string &subj, &body;
      
      Local string &content;
      Local string &bodytemp = %This.emailBody;
      
      If None(&bodytemp) Then
         
         &subj = &emailSubject | " | " | %OperatorId | "-" | %DbName | " | Debug Dumper | " | %Datetime;
         
         
         &body = "Attached you will find the debug dumper you requested. " | &crlf;
         &body = &body | "If you did not request this file, please contact your technical team and ignore this email." | &crlf;
         
         &body = &body | " Full File Name: " | &FullFileName;
      Else
         &body = %This.emailBody;
      End-If;
      
      SendMail(0, &tmpEmail, "", "", &subj, &body, &FullFileName, &UserFileName, "", ",", &content);
   End-If;
   
end-method;


method dumpLevelZero
   %This.dumpRowset(GetLevel0());
end-method;


method dumpCurrentRow
   %This.dumpRow(GetRow());
   
end-method;


method dump
   /+ &val as Any +/
   %This.dumpString(String(&val));
end-method;

method whiteSpace
   /+ &i as Integer +/
   If &i = 0 Then
      %This.dumpString("");
   Else
      Local integer &cnt;
      For &cnt = 1 To &i
         %This.dumpString("");
      End-For;
   End-If;
   
   
end-method;

get fileContents
   /+ Returns String +/
   
   Local string &return, &line;
   
   Local File &file = %This.openFile();
   
   While &file.ReadLine(&line);
      &return = &return | &line;
   End-While;
   
   Return &return;
end-get;



method dumpQueryString
   
   %This.dumpString(" _____BEGIN DUMP HTTP QUERY STRING ___ ");
   %This.dumpString("__Query String Parameters ___ ");
   
   %This.dumpString("Full Uri");
   %This.dumpString(%Request.RequestURI);
   %This.dumpString("Query String");
   %This.dumpString(%Request.QueryString);
   
   
   Local array of string &parmNames;
   Local integer &i;
   &parmNames = %Request.GetParameterNames();
   For &i = 1 To &parmNames.Len
      
      %This.dumpString("   " | &parmNames [&i] | ":" | %Request.GetParameter(&parmNames [&i]));
      
   End-For;
   %This.dumpString(" _____END DUMP HTTP QUERY STRING  ___ ");
   
   
   
end-method;



method dumpHTTPHeader
   %This.dumpString(" _____BEGIN DUMP HTTP HEADERS ___ ");
   
   Local array of string &hdrNames;
   Local integer &i;
   &hdrNames = %Request.GetHeaderNames();
   For &i = 1 To &hdrNames.Len
      
      %This.dumpString("   " | &hdrNames [&i] | ":" | %Request.GetHeader(&hdrNames [&i]));
      
   End-For;
   %This.dumpString(" _____END DUMP HTTP HEADERS ___ ");
   
end-method;




method dumpRowsetValuesAsCSV
   /+ &rs as Rowset, +/
   /+ &excludeFieldNames as String +/
   /* This only dumps the primary record */
   
   
   Local integer &rowCounter;
   Local integer &indentPreseve;
   
   &indentPreseve = %This.indentLevel;
   %This.indentLevel = %This.indentLevel + 4;
   
   Local integer &fieldNumber;
   
   Local Record &rec;
   
   Local string &csvrow;
   
   For &fieldNumber = 1 To &rs.GetRow(1).GetRecord(1).FieldCount
      
      If Find(&rs.GetRow(1).GetRecord(1).GetField(&fieldNumber).Name, &excludeFieldNames) <= 0 Then
         If &fieldNumber > 1 Then
            &csvrow = &csvrow | ",";
         End-If;
         
         
         &csvrow = &csvrow | &rs.GetRow(1).GetRecord(1).GetField(&fieldNumber).Name;
         
      End-If;
   End-For;
   %This.dump(&csvrow);
   For &rowCounter = 1 To &rs.RowCount
      
      &csvrow = "";
      For &fieldNumber = 1 To &rs.GetRow(&rowCounter).GetRecord(1).FieldCount
         If Find(&rs.GetRow(1).GetRecord(1).GetField(&fieldNumber).Name, &excludeFieldNames) <= 0 Then
            
            If &fieldNumber > 1 Then
               &csvrow = &csvrow | ",";
            End-If;
            &csvrow = &csvrow | &rs.GetRow(&rowCounter).GetRecord(1).GetField(&fieldNumber).Value;
         End-If;
      End-For;
      
      %This.dump(&csvrow);
      
      
      
   End-For; /* row loop */
   %This.indentLevel = &indentPreseve;
   
   
   
   
end-method;

