unit PlugServ;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  Windows, ActiveX, Classes, ComObj, CM2GenInterface, Filter, SysUtils,
   CM2AutoUpdateInterface, CM2EditorSupportInterface;

type
  TFileData = class(TComObject, ICM2GenPlug, ICM2AutoUpdate, ICM2EditorSupport10)
  private
   LastErrorMsg: String;
  protected
  // Declare Basics
   Function Name(OUT Name: Pchar): HResult; stdcall;
   Function Version(OUT Version: word): HResult; stdcall; // Using MMRB Notation
   Function RequiredCoreVersion(OUT RCV: Word): HResult; stdcall; // Using MMRB Notation - Please refer to CM2Plugtypes for details
   Function SetParentHandle(Handle: THandle): HResult; stdcall;
  // Declare Error commands
   Function GetLastErrorMsg(OUT Msg: PChar): HResult; stdcall;
  // Declare Info system
   Function GetInfoCount(OUT InfoCount: Integer): HResult; stdcall;
   Function GetInfo(Index: Integer; OUT InfoName: PChar; OUT InfoVar: PChar): HResult; stdcall;
  // Declare Sensor system
   Function GetSensorCount(OUT SensorCount: Integer): HResult; stdcall;
   Function GetSensorNameOnly(Index: Integer; OUT SensorName: PChar; OUT SensorStyle: Byte): HResult; stdcall; // Designed for speed polling at startup
   Function GetSensor(Index: Integer; Parameters: PChar; OUT SensorName: PChar; OUT SensorStyle: byte; OUT SensorString: PChar; OUT SensorValue: Double): HResult; stdcall;
  // Declare "Event" functions
   Function Init: HResult; stdcall;
   Function Terminating: HResult; stdcall;
   Function Setup: HResult; stdcall;
  // Declare Support types
   // Default (Required)
   Function GetDefaultCount(SensorIndex: Integer; OUT DefaultCount: Integer): HResult; stdcall;
   Function GetDefault(SensorIndex: Integer; Index: Integer; OUT Name: Pchar; OUT Value: PChar; OUT Description: PChar): HResult; stdcall;
   // Optional
   Function GetOptionalCount(SensorIndex: Integer; OUT OptionalCount: Integer): HResult; stdcall;
   Function GetOptional(SensorIndex: Integer; Index: Integer; OUT Name: Pchar; OUT Value: PChar; OUT Description: PChar): HResult; stdcall;
   // Auto update
   Function UpdateFileURL(OUT URL: Pchar): HResult; stdcall;
   // Editor Support
   Function ShowSensor(Index: Integer; OUT ShowAt: Byte): HResult; stdcall;
   Function ObjIns(SensorIndex: Integer; ParameterName: PChar; OUT ValueType: Byte; OUT ValueRange: PChar): HResult; stdcall;
  end;

const
  Class_FileData: TGUID = '{74AE9A69-3FE7-496B-A375-893E076AD04D}';
  AutoUpdateFile = 'http://www.coolmon.org/update/filedata.upd';


implementation

uses ComServ;

function IsStrFloatNum(s: string): Boolean; 
begin 
  try 
    // try to convert the string into a floatnumber 
    StrToFloat(s); 
    // if there is no error the result is true 
    Result := True; 
  except 
    // if there is any error the result is false 
    Result := False; 
  end; 
end;

{ TFileData }

function TFileData.GetDefault(SensorIndex, Index: Integer; out Name, Value,
  Description: PChar): HResult;
begin
 Case Index of
  0: begin Name := 'Filename'; Value := 'MyTestFile.txt'; Description := 'Full path to the file you want to poll data from'; end;
  1: Begin Name := 'Line'; Value := '1'; Description := 'The line number you want to poll, zero will provide last line'; end; 
 End;
 result := S_OK;
end;

function TFileData.GetDefaultCount(SensorIndex: Integer;
  out DefaultCount: Integer): HResult;
begin
 DefaultCount := 2;
 result := S_OK;
end;

function TFileData.GetInfo(Index: Integer; out InfoName,
  InfoVar: PChar): HResult;
begin
 Result := S_OK;
 Case Index of
  0: begin
      InfoName := 'Programmed By'; InfoVar := 'Christian Aaangel';
     End;
  1: begin
      InfoName := 'Created'; InfoVar := 'November 4th, 2003';
     End;
  2: begin
      InfoName := 'Updated'; InfoVar := 'June, 30th 2004';
     End;
  3: begin
      InfoName := 'Copyright'; InfoVar := '(c) 2003 - 2004, by Christian Aaangel';
     End;
  else
  begin
   Result := E_FAIL;
   LastErrorMsg := 'Index out of bounds';
  End;
 End;

end;

function TFileData.GetInfoCount(out InfoCount: Integer): HResult;
begin
 Result :=S_OK;
 InfoCount := 4;
end;

function TFileData.GetLastErrorMsg(OUT Msg: PChar): HResult;
begin
 If LastErrorMsg = '' then LastErrorMsg := 'No error';
 Msg := PChar(LastErrorMsg);
 Result := S_OK;
end;

function TFileData.GetOptional(SensorIndex, Index: Integer; out Name,
  Value, Description: PChar): HResult;
begin
 result := S_OK;
  Case Index of
   0: Begin Name := 'Start'; Value := '1'; Description := 'For adv. cutting - Will cut from the # Char to end of line, unless "Length" is defined'; end;
   1: Begin Name := 'Length'; Value := '5'; Description := 'Will read from "Start" Char and "Length" forward'; end;
  End;
end;

function TFileData.GetOptionalCount(SensorIndex: Integer;
  out OptionalCount: Integer): HResult;
begin
 OptionalCount := 2;
 result := S_OK;
end;

function TFileData.GetSensor(Index: Integer; Parameters: PChar;
  out SensorName: PChar; out SensorStyle: Byte; out SensorString: PChar;
  out SensorValue: Double): HResult;
Var
 Line, X, W: Integer;
 N, V, FName: String;
 Strings: TStrings;
 B: Byte;
 I: Integer;
begin
 Result := S_OK;
 Case Index of
  0: Begin
      GetSensorNameOnly(Index, SensorName, B);
      SensorStyle := 1;
      SensorString := 'Invalid Arguments';
      W := -1; X := 1; Line := 1;
      If Parameters = '' Then exit;
      Fname := '';
      For I := 1 to countfilt(Parameters, '|') do begin
       N := GetFilt(Parameters, I, '|');
       V := GetFilt(N, 2, '=');
       N := GetFilt(N, 1, '=');
       If Uppercase(N) = 'FILENAME' Then FName := V;
       If Uppercase(N) = 'LINE' then Line := StrToInt(V);
       If Uppercase(N) = 'START' then X := StrToInt(V);
       If Uppercase(N) = 'LENGTH' Then W := StrToInt(V);
      End;
      If Not fileexists(FName) then Begin
       SensorString := 'File does not exists';
       exit;
      End;
      Strings := TStringList.Create;
      Strings.LoadFromFile(FName);
      If Line < 1 then Line := Strings.Count - Line;
      Line := Line - 1;
      If W = -1 then W := Length(Strings[Line]);
      If IsStrFloatNum(Copy(Strings[Line], X, W)) Then begin
       SensorStyle := 0;
       SensorValue := StrToFloat(Copy(Strings[Line], X, W));
       SensorString := Pchar('');
      End
       else
      Begin
       SensorString := Pchar(Copy(Strings[Line], X, W));
      End;
      Result := S_OK;
      Strings.Free;
//      showmessage('[' + IntToStr(SensorStyle) + '] ' + sensorString + '[' + FloatToStr(SensorValue) + ']');
     End;
  Else begin
   Result := E_FAIL;
   LastErrorMsg := 'Index out of bounds';
  End;
 End;
end;

function TFileData.GetSensorCount(out SensorCount: Integer): HResult;
begin
 Result :=S_OK;
 SensorCount := 1;
end;

function TFileData.GetSensorNameOnly(Index: Integer;
  out SensorName: PChar; out SensorStyle: Byte): HResult;
begin
 Result := S_OK;
 SensorStyle := 2; // Unknown
 Case Index of
  0: SensorName := 'Filedata';
  else begin
   Result := E_FAIL;
   LastErrorMsg := 'Index out of bounds';
  end;
 End;
end;

function TFileData.Init: HResult;
begin
 Result := S_OK;
end;

function TFileData.Name(out Name: Pchar): HResult;
begin
 Name := 'Filedata';
 Result := S_OK;
end;

function TFileData.ObjIns(SensorIndex: Integer; ParameterName: PChar;
  out ValueType: Byte; out ValueRange: PChar): HResult;
begin
 ValueType := vtUnknown;
 Result := S_OK;
 If uppercase(parameterName) = 'FILENAME' then begin
  ValueType := vtFile;
  ValueRange := '';
 end;
end;

function TFileData.RequiredCoreVersion(out RCV: Word): HResult;
begin
 RCV := 0500;
 Result := S_OK;
end;

function TFileData.SetParentHandle(Handle: THandle): HResult;
begin
 Result := S_OK;
end;

function TFileData.Setup: HResult;
begin
 Result := E_NOTIMPL;
end;

function TFileData.ShowSensor(Index: Integer; out ShowAt: Byte): HResult;
begin
 Result := S_OK;
 ShowAt := saDesignTime;
end;

function TFileData.Terminating: HResult;
begin
 Result := S_OK;
end;

function TFileData.UpdateFileURL(out URL: Pchar): HResult;
begin
 URL := PChar(AutoUpdateFile);
 Result := S_OK;
end;

function TFileData.Version(out Version: word): HResult;
begin
 Version := 0501;
 Result := S_OK;
end;

initialization
  TComObjectFactory.Create(ComServer, TFileData, Class_FileData,
    'FileData', 'Filedata plugin for CM2', ciMultiInstance, tmApartment);
end.
