{***************************************************************************}
{ TMS Google Calendar access                                                }
{ for Delphi & C++Builder                                                   }
{                                                                           }
{ written by TMS Software                                                   }
{            copyright © 2012                                               }
{            Email : info@tmssoftware.com                                   }
{            Web : http://www.tmssoftware.com                               }
{                                                                           }
{ The source code is given as is. The author is not responsible             }
{ for any possible damage done due to the use of this code.                 }
{ The component can be freely used in any application. The complete         }
{ source code remains property of the author and may not be distributed,    }
{ published, given or sold in any form as such. No parts of the source      }
{ code can be included in any other component or application without        }
{ written authorization of the author.                                      }
{***************************************************************************}

unit CloudGCalendar;

interface

uses
  Classes, CloudBase, CloudGoogle, SysUtils, Windows, DBXJSON;

type
  TAdvGCalendar = class;
  TGCalendars = class;
  TGCalendarItems = class;
  TGCalendarItem = class;
  TGAttendees = class;

  TStatus = (stConfirmed, stTentative, stCancelled);
  TVisibility = (viPublic, viPrivate);
  TResponseStatus = (rsNeedsAction, rsDeclined, rsTentative, rsAccepted);

  TGAttendee = class(TCollectionItem)
  private
    FOwner: TGAttendees;
    FSummary: string;
    FEmail: string;
    FStatus: TResponseStatus;
    procedure SetEmail(const Value: string);
    procedure SetStatus(const Value: TResponseStatus);
    procedure SetSummary(const Value: string);
  public
    constructor Create(Collection: TCollection);  override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function GetOwner: TPersistent; override;
  protected
    function GetDisplayName: string; override;
  published
    property Summary: string read FSummary write SetSummary;
    property Email: string read FEmail write SetEmail;
    property Status: TResponseStatus read FStatus write SetStatus default rsNeedsAction;
  end;

  TGAttendees = class(TCollection)
  private
    FOwner: TGCalendarItem;
    function GetItems(Index: Integer): TGAttendee;
    procedure SetItems(Index: Integer; const Value: TGAttendee);
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    constructor Create(AOwner: TGCalendarItem);
    function GetOwner: TPersistent; override;
    function Add: TGAttendee;
    function Insert(Index: Integer):TGAttendee;
    property Items[Index: Integer]: TGAttendee read GetItems write SetItems; default;
  end;

  TGCalendar = class(TCollectionItem)
  private
    FOwner: TGCalendars;
    FSummary: string;
    FDescription: string;
    FID: string;
    procedure SetDescription(const Value: string);
    procedure SetID(const Value: string);
    procedure SetSummary(const Value: string);
  public
    constructor Create(Collection: TCollection);  override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function GetOwner: TPersistent; override;
  protected
    function GetDisplayName: string; override;
  published
    property ID: string read FID write SetID;
    property Summary: string read FSummary write SetSummary;
    property Description: string read FDescription write SetDescription;
  end;

  TGCalendars = class(TCollection)
  private
    FOwner: TAdvGCalendar;
    function GetItems(Index: Integer): TGCalendar;
    procedure SetItems(Index: Integer; const Value: TGCalendar);
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    constructor Create(AOwner: TAdvGCalendar);
    function GetOwner: TPersistent; override;
    function Add: TGCalendar;
    function Insert(Index: Integer):TGCalendar;
    property Items[Index: Integer]: TGCalendar read GetItems write SetItems; default;
  end;

  TGCalendarItem = class(TCollectionItem)
  private
    FOwner: TGCalendarItems;
    FLocation: string;
    FSummary: string;
    FStartTime: TDateTime;
    FEndTime: TDateTime;
    FDescription: string;
    FID: string;
    FVisibility: TVisibility;
//    FStatus: TStatus;
    FRecurrence: string;
    FCalendarID: string;
//    FOverlap: boolean;
    FAttendees: TGAttendees;
    FIsAllDay: boolean;
    FRecurringID: string;
    FETag: string;
    FSequence: integer;
    procedure SetDescription(const Value: string);
    procedure SetEndTime(const Value: TDateTime);
    procedure SetLocation(const Value: string);
    procedure SetSummary(const Value: string);
    procedure SetStartTime(const Value: TDateTime);
    procedure SetID(const Value: string);
//    procedure SetStatus(const Value: TStatus);
    procedure SetVisibility(const Value: TVisibility);
    procedure SetCalendarID(const Value: string);
    procedure SetIsAllDay(const Value: boolean);
//    procedure SetOverlap(const Value: boolean);
    procedure SetRecurrence(const Value: string);
    procedure SetRecurringID(const Value: string);
    procedure SetSequence(const Value: integer);

  public
    constructor Create(Collection: TCollection);  override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function GetOwner: TPersistent; override;
  protected
    function GetDisplayName: string; override;
  published
    property ID: string read FID write SetID;
    property ETag: string read FETag write FETag;
    property CalendarID: string read FCalendarID write SetCalendarID;
    property Summary: string read FSummary write SetSummary;
    property Description: string read FDescription write SetDescription;
    property StartTime: TDateTime read FStartTime write SetStartTime;
    property EndTime: TDateTime read FEndTime write SetEndTime;
    property IsAllDay: boolean read FIsAllDay write SetIsAllDay default false;
    property Location: string read FLocation write SetLocation;
//    property Status: TStatus read FStatus write SetStatus default stConfirmed;
    property Visibility: TVisibility read FVisibility write SetVisibility default viPublic;
    property Recurrence: string read FRecurrence write SetRecurrence;
    property RecurringID: string read FRecurringID write SetRecurringID;
//    property Overlap: boolean read FOverlap write SetOverlap default false;
    property Sequence: integer read FSequence write SetSequence;
    property Attendees: TGAttendees read FAttendees write FAttendees;
  end;

  TGCalendarItems = class(TCollection)
  private
    FOwner: TAdvGCalendar;
    function GetItems(Index: Integer): TGCalendarItem;
    procedure SetItems(Index: Integer; const Value: TGCalendarItem);
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    constructor Create(AOwner: TAdvGCalendar);
    function GetOwner: TPersistent; override;
    function Add: TGCalendarItem;
    function Find(const ID: integer): TGCalendarItem; overload;
    function Find(const ID: string): TGCalendarItem; overload;
    function Insert(Index: Integer): TGCalendarItem;
    function GetItemByID(const ID: string): TGCalendarItem;
    property Items[Index: Integer]: TGCalendarItem read GetItems write SetItems; default;
  end;

  TAdvGCalendar = class(TCloudGoogle)
  private
    APIBase: string;
    FItems: TGCalendarItems;
    FResult: TGCalendarItems;
    FCalendars: TGCalendars;
  protected
    function GetCalendarData(Item: TGCalendarItem): string;
    procedure ParseCalendarItem(CalendarID: string; jo: TJSONObject; Item: TGCalendaritem);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure GetCalendars;
    procedure GetCalendar(ID: string; FromDate, ToDate: TDate); overload;
    procedure GetCalendar(FromDate, ToDate: TDate); overload;
    procedure GetCalendar(ID: string); overload;
    function GetItemByID(CalendarID, ItemID: string): TGCalendarItem;
    procedure Add(Item: TGCalendarItem);
    procedure Update(Item: TGCalendarItem);
    procedure Delete(Item: TGCalendarItem);
  published
    property Calendars: TGCalendars read FCalendars write FCalendars;
    property Items: TGCalendarItems read FItems write FItems;
  end;

implementation

uses
  Dialogs;

{ TAdvGCalendar }

constructor TAdvGCalendar.Create(AOwner: TComponent);
begin
  inherited;
  APIBase := 'https://www.googleapis.com';

  FCalendars := TGCalendars.Create(Self);
  FItems := TGCalendarItems.Create(self);
  FResult := TGCalendarItems.Create(self);

  //required scopes
  Scopes.Add('https://www.googleapis.com/auth/calendar');
end;

destructor TAdvGCalendar.Destroy;
begin
  FResult.Free;
  FCalendars.Free;
  FItems.Free;
  inherited;
end;

procedure TAdvGCalendar.GetCalendar(ID: string);
begin
  GetCalendar(ID, 0, 0);
end;

procedure ParseJSON(Data: string; var JSONObject: TJSONObject);
var
  StringBytes: TBytes;
begin
  StringBytes := TEncoding.ASCII.GetBytes(data);
  JSONObject.Parse(StringBytes,0);
end;

procedure TAdvGCalendar.GetCalendar(ID: string; FromDate, ToDate: TDate);
var
  url: string;
  o, fo: TJSONObject;
  ja: TJSONArray;
  i: integer;
  item: TGCalendarItem;
  resdat: ansistring;
  strRes: string;
  headers: TCoreCloudHeaders;
  jv: TJSONValue;
begin
  url := APIBase + '/calendar/v3/calendars/' + URLEncode(ID) + '/events';

  //load items in chronological order
  //get instances of recurrent items
  url := url + '?key=' + App.Key + '&singleEvents=True&orderBy=startTime';
  //load items in order of creation
  //get parent recurrent item only
  //url := url + '?key=' + App.Key;

  if (FromDate <> 0) and (ToDate <> 0)  then
  begin
    url := url + '&timeMin=' + URLEncode(DateTimeToWL(FromDate))
      + '&timeMax=' + URLEncode(DateTimeToWL(ToDate));
  end;

  AddHeader(headers, 'Authorization', 'Bearer ' + Token_Access  + #13#10);
  AddHeader(headers, 'Content- Type', 'application/json');

  resdat := HttpsGet(url, headers);
  strRes := UTF8ToString(resdat);

//  OutputDebugString(pchar('ITEM LIST ' + strRes));

  strRes := StringReplace(strRes, #10, '', [rfReplaceAll]);
  strRes := StringReplace(strRes, #13, '', [rfReplaceAll]);

  strres := string(CleanUpJSON(ansistring(strres)));

  jv := TJSONObject.ParseJSONValue(strres);

  Items.Clear;

  if Assigned(jv) and (jv is TJSONObject) then
  begin
    try
      o := jv as TJSONObject;
      ja := GetJSONValue(o,'items') as TJSONArray;

      if Assigned(ja) then
      begin
        for i := 0 to ja.Size - 1 do
        begin
          fo := ja.Get(i) as TJSONObject;
          if Assigned(fo) then
          begin
            item := Items.Add;
            ParseCalendarItem(ID, fo, item);
          end;
        end;
      end;
    finally
      jv.Free;
    end;
  end;
end;

procedure TAdvGCalendar.GetCalendar(FromDate, ToDate: TDate);
begin
  GetCalendar(EmptyStr, FromDate, ToDate);
end;

function TAdvGCalendar.GetCalendarData(Item: TGCalendarItem): string;
var
  vis, starttime, endtime, att: string;
  I: integer;
begin

//  case Item.Status of
//    stConfirmed: stat := 'confirmed';
//    stTentative: stat := 'tentative';
//    stCancelled: stat := 'cancelled';
//  end;

  case Item.Visibility of
    viPublic: vis := 'public';
    viPrivate: vis := 'private';
  end;

//  if item.Overlap then
//    transp := 'transparent'
//  else
//    transp := 'opaque';

  if Item.IsAllDay then
  begin
    starttime := '"date": "' + FormatDateTime('yyyy-MM-dd', Item.StartTime) + '"';
    endtime := '"date": "' + FormatDateTime('yyyy-MM-dd', Item.EndTime) + '"';
  end
  else
  begin
    starttime := '"dateTime": "' + DateTimeToWL(Item.StartTime) + '"';
    endtime := '"dateTime": "' + DateTimeToWL(Item.EndTime) + '"';
  end;

  if Item.Attendees.Count > 0 then
  begin
    att := ', "attendees":[';

    for I := 0 to Item.Attendees.Count - 1 do
    begin
      if I > 0 then
        att := att + ',';
      att := att + '{"email":"' + Item.Attendees[I].Email + '","displayName":"' + Item.Attendees[I].Summary + '"}';
    end;

    att := att + ']';
  end;

  result :=
  '{' + #13#10
  + '    "summary": "' + Item.Summary +'",' + #13#10
  + '    "description": "' + Item.Description + '",' + #13#10
  + '    "start": { ' + starttime + ' },' + #13#10
  + '    "end": { ' + endtime + ' },' + #13#10
  + '    "location": "' + Item.Location + '", ' + #13#10
  //Increment sequence value to enable updating the start time of a calendar item
  + '    "sequence": "' + IntToStr(Item.Sequence+1) + '", ' + #13#10
  + '    "visibility": "' + vis + '"' + #13#10
  + att
  + '}';

//  + '    "transparency": "' + transp + '",' + #13#10
//  + '    "status": "' + stat + '", ' + #13#10

//  OutputDebugString(pchar('UPDATE ITEM: ' + result))
end;

procedure TAdvGCalendar.GetCalendars;
var
  url: string;
  o, fo: TJSONObject;
  ja: TJSONArray;
  di: TGCalendar;
  i: integer;
  resdat: ansistring;
  headers: TCoreCloudHeaders;
  resstr: string;
  jv: TJSONValue;
begin
  url := APIBase + '/calendar/v3/users/me/calendarList';
  url := url + '?key=' + App.Key;


  AddHeader(headers, 'Authorization', 'Bearer ' + Token_Access  + #13#10);
  AddHeader(headers, 'Content- Type', 'application/json');

  resdat := HttpsGet(url, headers);
  resstr := UTF8ToString(resdat);

  jv := TJSONObject.ParseJSONValue(resstr);

  Calendars.Clear;

  if Assigned(jv) and (jv is TJSONObject) then
  begin
    o := jv as TJSONObject;
    try
      ja := GetJSONValue(o,'items') as TJSONArray;
      if Assigned(ja) then
      begin
        for i := 0 to ja.Size - 1 do
        begin
          fo := ja.Get(i) as TJSONObject;

          di := Calendars.Add;
          di.ID := GetJSONProp(fo,'id');
          di.Summary := GetJSONProp(fo,'summary');
          di.Description := GetJSONProp(fo,'description');
        end;
      end;
    finally
      jv.Free;
    end;
  end;
end;

function TAdvGCalendar.GetItemByID(CalendarID, ItemID: string): TGCalendarItem;
var
  headers: TCoreCloudHeaders;
  url, strRes: string;
  resdat: ansistring;
  jo: TJSONObject;
  jv: TJSONValue;
begin
  Result := nil;
  FResult.Clear;

  url := APIBase + '/calendar/v3/calendars/' + URLEncode(CalendarID) + '/events/' + URLEncode(ItemID);
  url := url + '?key=' + App.Key;

  AddHeader(headers, 'Authorization', 'Bearer ' + Token_Access  + #13#10);
  AddHeader(headers, 'Content-Type', 'application/json');

  resdat := HttpsGet(url, headers);
  strRes := UTF8ToString(resdat);

  strRes := StringReplace(strRes, #10, '', [rfReplaceAll]);
  strRes := StringReplace(strRes, #13, '', [rfReplaceAll]);
  strres := string(CleanUpJSON(ansistring(strres)));

  if (Pos('"recurrence":', strres) > 0) then
  begin
    Result := FResult.Add;
    jv := TJSONObject.ParseJSONValue(strres);
    if Assigned(jv) and (jv is TJSONObject) then
    begin
      try
        jo := jv as TJSONObject;
        ParseCalendarItem(CalendarID, jo, Result);
      finally
        jv.Free;
      end;
    end;
  end;
end;

procedure TAdvGCalendar.ParseCalendarItem(CalendarID:string; jo: TJSONObject; Item: TGCalendaritem);
var
  vis, rstat: string;
  ffo: TJSONObject;
  fja: TJSONArray;
  j: integer;
  di: TGCalendarItem;
  ai: TGAttendee;
  jp: TJSONPair;
begin
//  OutputDebugString(pchar('ITEM: ' + StrJSON));
  di := Item;
  di.CalendarID := CalendarID;
  di.ID := GetJSONProp(jo,'id');

  jp := jo.Get('summary');
  if Assigned(jp) then
    di.Summary := GetJSONProp(jo,'summary')
  else
    di.Summary := EmptyStr;

  jp := jo.Get('etag');
  if Assigned(jp) then
    di.ETag := GetJSONProp(jo,'etag')
  else
    di.ETag := EmptyStr;

  jp := jo.Get('sequence');
  if Assigned(jp) then
    di.Sequence := StrToInt(GetJSONProp(jo,'sequence'))
  else
    di.Sequence := 0;

  jp := jo.Get('description');
  if Assigned(jp) then
    di.Description := GetJSONProp(jo,'description')
  else
    di.Description := EmptyStr;

  jp := jo.Get('location');
  if Assigned(jp) then
    di.Location := GetJSONProp(jo,'location')
  else
    di.Location := EmptyStr;

    //        if (Pos('"status":', fo.ToString) > 0) then
    //        begin
    //          stat := GetJSONProp(fo,'status');
    //          if stat = 'confirmed' then
    //            di.Status := stConfirmed
    //          else if stat = 'tentative' then
    //            di.Status := stTentative
    //          else if stat = 'cancelled' then
    //            di.Status := stCancelled;
    //        end;

  jp := jo.Get('visibility');
  if Assigned(jp) then
    vis := GetJSONProp(jo,'visibility')
  else
    vis := EmptyStr;

  if (vis = 'private') then
    di.Visibility := viPrivate
  else
    di.Visibility := viPublic;

  jp := jo.Get('recurrence');
  if Assigned(jp) then
  begin
    di.Recurrence := GetJSONValue(jo,'recurrence').ToString;
    di.Recurrence := StringReplace(di.Recurrence, '"', '', [rfReplaceAll]);
    di.Recurrence := StringReplace(di.Recurrence, '[', '', [rfReplaceAll]);
    di.Recurrence := StringReplace(di.Recurrence, ']', '', [rfReplaceAll]);
  end;

  jp := jo.Get('recurringEventId');

  if Assigned(jp) then
    di.FRecurringID := GetJSONProp(jo,'recurringEventId');

//        if (Pos('"transparency":', fo.ToString) > 0) then
//          transp := GetJSONProp(fo,'recurringEventId')
//        else
//          transp := 'opaque';
//
//        if (transp = 'opaque') then
//          di.Overlap := false
//        else
//          di.Overlap := true;

  jp := jo.Get('start');
  if Assigned(jp) then
  begin
//    ffo := TJSONObject.Create;
    ffo := GetJSONValue(jo,'start') as TJSONObject;

    jp := ffo.Get('dateTime');
    if Assigned(jp) then
    begin
      di.StartTime := IsoToDateTime(GetJSONProp(ffo,'dateTime'));
      di.IsAllDay := false;
    end
    else
    begin
      jp := ffo.Get('date');
      if Assigned(jp) then
      begin
        di.StartTime := IsoToDate(GetJSONProp(ffo,'date'));
        di.IsAllDay := true;
      end;
    end;
  end;

  jp := jo.Get('end');
  if Assigned(jp) then
  begin
//    ffo := TJSONObject.Create;
    ffo := GetJSONValue(jo,'end') as TJSONObject;

//          OutputDebugString(pchar('EVENT END TIME= ' + ffo.ToString + ' ** ' + GetJSONProp(ffo,'dateTime')));

    jp := ffo.Get('dateTime');
    if Assigned(jp) then
    begin
      di.EndTime := IsoToDateTime(GetJSONProp(ffo,'dateTime'));
      di.IsAllDay := false;
    end
    else
    begin
      jp := ffo.Get('date');
      if Assigned(jp) then
      begin
        di.EndTime := IsoToDate(GetJSONProp(ffo,'date'));
        di.IsAllDay := true;
      end;
    end;
  end;

  jp := jo.Get('attendees');
  if Assigned(jp) then
  begin
    fja := GetJSONValue(jo,'attendees') as TJSONArray;

    if Assigned(fja) then
    begin
      di.Attendees.Clear;
      for j := 0 to fja.Size - 1 do
      begin
        ffo := fja.Get(j) as TJSONObject;

        ai := di.Attendees.Add;

        jp := ffo.Get('responseStatus');
        if Assigned(jp) then
          rstat := GetJSONProp(ffo,'responseStatus')
        else
          rstat := EmptyStr;

        if rstat = 'needsAction' then
          ai.Status := rsNeedsAction
        else if rstat = 'declined' then
          ai.Status := rsDeclined
        else if rstat = 'tentative' then
          ai.Status := rsTentative
        else if rstat = 'accepted' then
          ai.Status := rsAccepted;

        jp := ffo.Get('displayName');

        if Assigned(jp) then
          ai.Summary := GetJSONProp(ffo,'displayName')
        else
          ai.Summary := EmptyStr;

        jp := ffo.Get('email');
        if Assigned(jp) then
          ai.Email := GetJSONProp(ffo,'email')
        else
          ai.Email := EmptyStr;
      end;
    end;
  end;
end;

procedure TAdvGCalendar.Add(Item: TGCalendarItem);
var
  headers: TCoreCloudHeaders;
  resdat, data: ansistring;
  url: string;
begin

  AddHeader(headers, 'Authorization', 'Bearer ' + Token_Access  + #13#10);
  AddHeader(headers, 'Content-Type', 'application/json');

  data := UTF8Encode(GetCalendarData(Item));

  url := APIBase + '/calendar/v3/calendars/' + URLEncode(Item.CalendarID)
    + '/events?key=' + App.Key;

  HttpsPost(ExtractServer(url),RemoveServer(url),headers,data,resdat);
//  OutputDebugString(pchar('ADD RESULT: ' + string(resdat)));
end;

procedure TAdvGCalendar.Delete(Item: TGCalendarItem);
var
  headers: TCoreCloudHeaders;
  url: string;
  resdat, data: ansistring;
begin
  url := APIBase + '/calendar/v3/calendars/' + URLEncode(Item.CalendarID)
    + '/events/' + URLEncode(Item.ID) + '?key=' + App.Key + '&access_token=' + Token_Access;

  AddHeader(headers, 'Authorization', 'Bearer ' + Token_Access  + #13#10);
//  + #13#10
//  +'Content-Type: application/json';

  data := '';

  HttpsDelete(ExtractServer(url),RemoveServer(url),headers,data,resdat);

//  OutputDebugString(pchar('DELETE: ' + string(resdat)));
end;

procedure TAdvGCalendar.Update(Item: TGCalendarItem);
var
  headers: TCoreCloudHeaders;
  resdat, data: ansistring;
  url: string;
begin
  AddHeader(headers, 'Authorization', 'Bearer ' + Token_Access  + #13#10);
  AddHeader(headers, 'Content-Type', 'application/json'#13#10);

  data := ansistring(GetCalendarData(Item));

  url := APIBase + '/calendar/v3/calendars/' + URLEncode(Item.CalendarID)
    + '/events/' + URLEncode(Item.ID) + '?key=' + App.Key;

  HttpsUpdate(ExtractServer(url),RemoveServer(url),headers,data,resdat);

//  OutputDebugString(pchar('Result UPDATE := ' + string(resdat)));
end;


{ TGCalendarItem }

procedure TGCalendarItem.Assign(Source: TPersistent);
begin
  if (Source is TGCalendarItem) then
  begin
    FID := (Source as TGCalendarItem).ID;
    FCalendarID := (Source as TGCalendarItem).CalendarID;
    FSummary := (Source as TGCalendarItem).Summary;
    FDescription := (Source as TGCalendarItem).Description;
    FStartTime := (Source as TGCalendarItem).StartTime;
    FEndTime := (Source as TGCalendarItem).EndTime;
    FLocation := (Source as TGCalendarItem).Location;
//    FStatus := (Source as TGCalendarItem).Status;
    FVisibility := (Source as TGCalendarItem).Visibility;
    FRecurrence := (Source as TGCalendarItem).Recurrence;
    FRecurringID := (Source as TGCalendarItem).RecurringID;
    FIsAllDay := (Source as TGCalendarItem).IsAllDay;
//    FOverlap := (Source as TGCalendarItem).Overlap;
    FAttendees := (Source as TGCalendarItem).Attendees;
  end;
end;

constructor TGCalendarItem.Create(Collection: TCollection);
begin
  inherited;
  FID := EmptyStr;
  FCalendarID := EmptyStr;
  FSummary := 'Item ' + IntToStr(Collection.Count - 1);
  FDescription := EmptyStr;
  FStartTime := Date;
  FEndTime := Date;
  FLocation := EmptyStr;
//  FStatus := stConfirmed;
  FVisibility := viPublic;
  FRecurrence := EmptyStr;
  FRecurringID := EmptyStr;
//  FOverlap := false;
  FIsAllDay := false;
  FAttendees := TGAttendees.Create(Self);
  FSequence := -1;

  if Collection is TGCalendarItems then
  begin
    FOwner := Collection as TGCalendarItems;
  end;
end;

destructor TGCalendarItem.Destroy;
begin
  FAttendees.Free;
  inherited;
end;

function TGCalendarItem.GetDisplayName: string;
begin
  if Summary <> '' then
    Result := Summary
  else
    Result := 'Item '+ IntToStr(Index);
end;

function TGCalendarItem.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

//procedure TGCalendarItem.SetStatus(const Value: TStatus);
//begin
//  FStatus := Value;
//end;

procedure TGCalendarItem.SetCalendarID(const Value: string);
begin
  FCalendarID := Value;
end;

procedure TGCalendarItem.SetDescription(const Value: string);
begin
  FDescription := Value;
end;

procedure TGCalendarItem.SetEndTime(const Value: TDateTime);
begin
  FEndTime := Value;
end;

procedure TGCalendarItem.SetID(const Value: string);
begin
  FID := Value;
end;

procedure TGCalendarItem.SetIsAllDay(const Value: boolean);
begin
  FIsAllDay := Value;
end;

procedure TGCalendarItem.SetLocation(const Value: string);
begin
  FLocation := Value;
end;

procedure TGCalendarItem.SetSummary(const Value: string);
begin
  FSummary := Value;
end;

//procedure TGCalendarItem.SetOverlap(const Value: boolean);
//begin
//  FOverlap := Value;
//end;

procedure TGCalendarItem.SetRecurrence(const Value: string);
begin
  FRecurrence := Value;
end;

procedure TGCalendarItem.SetRecurringID(const Value: string);
begin
  FRecurringID := Value;
end;

procedure TGCalendarItem.SetSequence(const Value: integer);
begin
  FSequence := Value;
end;

procedure TGCalendarItem.SetStartTime(const Value: TDateTime);
begin
  FStartTime := Value;
end;

procedure TGCalendarItem.SetVisibility(const Value: TVisibility);
begin
  FVisibility := Value;
end;

{ TGCalendarItems }

function TGCalendarItems.Add: TGCalendarItem;
begin
  Result := TGCalendarItem(inherited Add);
end;

constructor TGCalendarItems.Create(AOwner: TAdvGCalendar);
begin
  inherited Create(TGCalendarItem);
  FOwner := AOwner;
end;

function TGCalendarItems.Find(const ID: integer): TGCalendarItem;
begin
  Result := Find(IntToStr(ID));
end;

function TGCalendarItems.Find(const ID: string): TGCalendarItem;
var
  i: integer;
begin
  Result := nil;

  for i := 0 to Count - 1 do
  begin
    if Items[i].ID = ID then
    begin
      Result := Items[i];
      break;
    end;
  end;
end;

function TGCalendarItems.GetItemByID(const ID: string): TGCalendarItem;
var
  i: integer;
begin
  Result := nil;

  for i := 0 to Count - 1 do
  begin
    if Items[i].ID = ID then
    begin
      Result := Items[i];
      break;
    end;
  end;
end;

function TGCalendarItems.GetItems(Index: Integer): TGCalendarItem;
begin
  Result := TGCalendarItem(inherited Items[Index]);
end;

function TGCalendarItems.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

function TGCalendarItems.Insert(Index: Integer): TGCalendarItem;
begin
  Result := TGCalendarItem(inherited Insert(Index));
end;

procedure TGCalendarItems.SetItems(Index: Integer;
  const Value: TGCalendarItem);
begin
  inherited Items[Index] := Value;
end;

procedure TGCalendarItems.Update(Item: TCollectionItem);
begin
  inherited;
end;


{ TGCalendar }

procedure TGCalendar.Assign(Source: TPersistent);
begin
  if (Source is TGCalendar) then
  begin
    FID := (Source as TGCalendar).ID;
    FSummary := (Source as TGCalendar).Summary;
    FDescription := (Source as TGCalendar).Description;
  end;
end;

constructor TGCalendar.Create(Collection: TCollection);
begin
  inherited;
  FID := EmptyStr;
  FSummary := 'Item ' + IntToStr(Collection.Count - 1);
  FDescription := EmptyStr;

  if Collection is TGCalendars then
  begin
    FOwner := Collection as TGCalendars;
  end;
end;

destructor TGCalendar.Destroy;
begin
  inherited;
end;

function TGCalendar.GetDisplayName: string;
begin
  if Summary <> '' then
    Result := Summary
  else
    Result := 'Calendar '+ IntToStr(Index);
end;

function TGCalendar.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TGCalendar.SetDescription(const Value: string);
begin
  FDescription := Value;
end;

procedure TGCalendar.SetID(const Value: string);
begin
  FID := Value;
end;

procedure TGCalendar.SetSummary(const Value: string);
begin
  FSummary := Value;
end;

{ TGCalendars }

function TGCalendars.Add: TGCalendar;
begin
  Result := TGCalendar(inherited Add);
end;

constructor TGCalendars.Create(AOwner: TAdvGCalendar);
begin
  inherited Create(TGCalendar);
  FOwner := AOwner;
end;

function TGCalendars.GetItems(Index: Integer): TGCalendar;
begin
  Result := TGCalendar(inherited Items[Index]);
end;

function TGCalendars.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

function TGCalendars.Insert(Index: Integer): TGCalendar;
begin
  Result := TGCalendar(inherited Insert(Index));
end;

procedure TGCalendars.SetItems(Index: Integer; const Value: TGCalendar);
begin
  inherited Items[Index] := Value;
end;

procedure TGCalendars.Update(Item: TCollectionItem);
begin
  inherited;
end;

{ TGAttendee }

procedure TGAttendee.Assign(Source: TPersistent);
begin
  if (Source is TGAttendee) then
  begin
    FEmail := (Source as TGAttendee).Email;
    FSummary := (Source as TGAttendee).Summary;
    FStatus := (Source as TGAttendee).Status
  end;
end;

constructor TGAttendee.Create(Collection: TCollection);
begin
  inherited;
  FEmail := EmptyStr;
  FSummary := 'Attendee ' + IntToStr(Collection.Count - 1);
  FStatus := rsNeedsAction;

  if Collection is TGAttendees then
  begin
    FOwner := Collection as TGAttendees;
  end;
end;

destructor TGAttendee.Destroy;
begin
  inherited;
end;

function TGAttendee.GetDisplayName: string;
begin
  if Summary <> '' then
    Result := Summary
  else
    Result := 'Attendee '+ IntToStr(Index);
end;

function TGAttendee.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TGAttendee.SetEmail(const Value: string);
begin
  FEmail := Value;
end;

procedure TGAttendee.SetStatus(const Value: TResponseStatus);
begin
  FStatus := Value;
end;

procedure TGAttendee.SetSummary(const Value: string);
begin
  FSummary := Value;
end;

{ TGAttendees }

function TGAttendees.Add: TGAttendee;
begin
  Result := TGAttendee(inherited Add);
end;

constructor TGAttendees.Create(AOwner: TGCalendarItem);
begin
  inherited Create(TGAttendee);
  FOwner := AOwner;
end;

function TGAttendees.GetItems(Index: Integer): TGAttendee;
begin
  Result := TGAttendee(inherited Items[Index]);
end;

function TGAttendees.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

function TGAttendees.Insert(Index: Integer): TGAttendee;
begin
  Result := TGAttendee(inherited Insert(Index));
end;

procedure TGAttendees.SetItems(Index: Integer; const Value: TGAttendee);
begin
  inherited Items[Index] := Value;
end;

procedure TGAttendees.Update(Item: TCollectionItem);
begin
  inherited;
end;

end.
