unit untCardJson;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, untCard, fpjson, fpjsonrtti, jsonparser, jsonscanner;

type

  { TCardJson }

  TCardJson = class
  public
    class function CardToJson(ACard: TCard): TJSONData;
    class function JsonToCard(AJson: TJSONData): TCard;
  end;

  { TPuzzleJson }

  TPuzzleJson = class
  public
    class function PuzzleToJson(APuzzle: TPuzzleField): string;
    class function JsonToPuzzle(AJsonString: String): TPuzzleField;
  end;

function CardTypeToStr(ct: TCardType): String;
function StrToCardType(str: String): TCardType;
function CardLocationToStr(cl: TCardLocation): String;
function StrToCardLocation(str: String): TCardLocation;
function CardOwnerToStr(co: TCardOwner): string;
function StrToCardOwner(str: String): TCardOwner;
function CardPlayerToStr(cp: TCardPlayer): string;
function StrToCardPlayer(str: String): TCardPlayer;
function CardPositionToStr(cp: TCardPosition): string;
function StrToCardPosition(str: string): TCardPosition;
function CardWorkAsToStr(cwa: TCardWorkAs): string;
function StrToCardWorkAs(str: string): TCardWorkAs;


implementation

{ TCardJson }

class function TCardJson.CardToJson(ACard: TCard): TJSONData;
var
  json: TJSONObject;
  jarr: TJSONArray;
  i: Integer;
begin
  if ACard = nil then Exit(TJSONNull.Create());
  json := TJSONObject.Create();
  json.Int64s['cardId'] := ACard.CardId;
  json.Strings['cardName'] := ACard.CardName;
  json.Strings['cardType'] := CardTypeToStr(ACard.CardType);
  jarr := TJSONArray.Create();
  for i := 0 to ACard.ContinousEffectTo.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(ACard.ContinousEffectTo[i]));
  end;
  json.Arrays['continousEffectTo'] := jarr;
  json.Objects['equipTo'] := TJSONObject(TCardJson.CardToJson(ACard.EquipTo));
  json.Integers['indicatorCount'] := ACard.IndicatorCount;
  json.Booleans['isLinkMonster'] := ACard.IsLinkMonster;
  json.Booleans['isXyzMonster'] := ACard.IsXyzMonster;
  json.Strings['location'] := CardLocationToStr(ACard.Location);
  json.Strings['owner'] := CardOwnerToStr(ACard.Owner);
  json.Strings['player'] := CardPlayerToStr(ACard.Player);
  json.Strings['position'] := CardPositionToStr(ACard.Position);
  json.Booleans['proc'] := ACard.Proc;
  json.Integers['seq'] := ACard.Seq;
  jarr := TJSONArray.Create();
  for i := 0 to ACard.XyzElements.Count - 1 do begin
    jarr.Add(ACard.XyzElements[i]);
  end;
  json.Arrays['xyzElements'] := jarr;
  json.Strings['workAs'] := CardWorkAsToStr(ACard.WorkAs);
  Exit(json);
end;

class function TCardJson.JsonToCard(AJson: TJSONData): TCard;
var
  c: TCard;
  j: TJSONObject;
  jarr: TJSONArray;
  i: Integer;
  jd: TJSONData;
begin
  if AJson = nil then Exit(nil);
  if AJson.IsNull then Exit(nil);
  j := TJSONObject(AJson);
  c := TCard.Create;
  c.CardId := j.Int64s['cardId'];
  c.CardName := j.Strings['cardName'];
  c.CardType := StrToCardType(j.Strings['cardType']);
  jarr := j.Arrays['continousEffectTo'];
  for i:= 0 to jarr.Count - 1 do begin
    c.ContinousEffectTo.Add(TCardJson.JsonToCard(jarr.Objects[i]));
  end;
  jd := j.Find('equipTo');
  c.EquipTo := TCardJson.JsonToCard(jd);
  c.IndicatorCount := j.Integers['indicatorCount'];
  c.IsLinkMonster := j.Booleans['isLinkMonster'];
  c.IsXyzMonster := j.Booleans['isXyzMonster'];
  c.Location := StrToCardLocation(j.Strings['location']);
  c.Owner := StrToCardOwner(j.Strings['owner']);
  c.Player := StrToCardPlayer(j.Strings['player']);
  c.Position := StrToCardPosition(j.Strings['position']);
  c.Proc := j.Booleans['proc'];
  c.Seq := j.Integers['seq'];
  jarr := j.Arrays['xyzElements'];
  for i:= 0 to jarr.Count - 1 do begin
    c.XyzElements.Add(jarr.Int64s[i]);
  end;
  c.WorkAs:= StrToCardWorkAs(j.Strings['workAs']);

  Exit(c);
end;

class function TPuzzleJson.PuzzleToJson(APuzzle: TPuzzleField): string;
var
  json: TJSONObject;
  jarr: TJSONArray;
  i, j: Integer;
  str: String;
begin
  json := TJSONObject.Create();

  json.Int64s['puzzleId'] := APuzzle.PuzzleId;
  json.Strings['puzzleName'] := APuzzle.PuzzleName;

  json.Strings['aiName'] := APuzzle.AIName;

  jarr := TJSONArray.Create;
  for i := 0 to 4 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.MCard[0, i]));
  end;
  json.Arrays['p0MCards'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to 4 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.MCard[1, i]));
  end;
  json.Arrays['p1MCards'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to 5 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.SCard[0, i]));
  end;
  json.Arrays['p0SCards'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to 5 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.SCard[1, i]));
  end;
  json.Arrays['p1SCards'] := jarr;

  jarr := TJSONArray.Create;
  for i := 5 to 6 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.ExtraMonster[i]));
  end;
  json.Arrays['extraMonsters'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P0Deck.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P0Deck[i]));
  end;
  json.Arrays['p0Deck'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P1Deck.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P1Deck[i]));
  end;
  json.Arrays['p1Deck'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P0ExtraDeck.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P0ExtraDeck[i]));
  end;
  json.Arrays['p0ExtraDeck'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P1ExtraDeck.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P1ExtraDeck[i]));
  end;
  json.Arrays['p1ExtraDeck'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P0Grave.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P0Grave[i]));
  end;
  json.Arrays['p0Grave'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P1Grave.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P1Grave[i]));
  end;
  json.Arrays['p1Grave'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P0Hand.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P0Hand[i]));
  end;
  json.Arrays['p0Hand'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P1Hand.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P1Hand[i]));
  end;
  json.Arrays['p1Hand'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P0Removed.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P0Removed[i]));
  end;
  json.Arrays['p0Removed'] := jarr;

  jarr := TJSONArray.Create;
  for i := 0 to APuzzle.P1Removed.Count - 1 do begin
    jarr.Add(TCardJson.CardToJson(APuzzle.P1Removed[i]));
  end;
  json.Arrays['p1Removed'] := jarr;

  json.Integers['p0life'] := APuzzle.LPSelf;
  json.Integers['p1life'] := APuzzle.LPOpponent;
  json.Strings['message'] := APuzzle.Message;
  json.Strings['solution'] := APuzzle.Solution;

  str := json.AsJSON;
  json.Free;
  Exit(str);
end;

class function TPuzzleJson.JsonToPuzzle(AJsonString: String): TPuzzleField;
var
  puz: TPuzzleField;
  p: TJSONParser;
  j: TJSONObject;
  jarr: TJSONArray;
  jobj: TJSONObject;
  i: Integer;
begin
  p := TJSONParser.Create(AJsonString, [joUTF8]);
  j := TJSONObject(p.Parse());

  puz := TPuzzleField.Create;

  puz.PuzzleId:= j.Int64s['puzzleId'];
  puz.PuzzleName:= j.Strings['puzzleName'];

  puz.AIName := j.Strings['aiName'];

  for i := 0 to 4 do begin
    puz.MCard[0, i] := TCardJson.JsonToCard(j.Arrays['p0MCards'].Items[i]);
  end;
  for i := 0 to 4 do begin
    puz.MCard[1, i] := TCardJson.JsonToCard(j.Arrays['p1MCards'].Items[i]);
  end;
  for i := 0 to 5 do begin
    puz.SCard[0, i] := TCardJson.JsonToCard(j.Arrays['p0SCards'].Items[i]);
  end;
  for i := 0 to 5 do begin
    puz.SCard[1, i] := TCardJson.JsonToCard(j.Arrays['p1SCards'].Items[i]);
  end;
  for i := 5 to 6 do begin
    puz.ExtraMonster[i] := TCardJson.JsonToCard(j.Arrays['extraMonsters'].Items[i - 5]);
  end;
  
  jarr := j.Arrays['p0Deck'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P0Deck.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  jarr := j.Arrays['p1Deck'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P1Deck.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  jarr := j.Arrays['p0ExtraDeck'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P0ExtraDeck.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  jarr := j.Arrays['p1ExtraDeck'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P1ExtraDeck.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  jarr := j.Arrays['p0Grave'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P0Grave.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  jarr := j.Arrays['p1Grave'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P1Grave.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  jarr := j.Arrays['p0Hand'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P0Hand.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  jarr := j.Arrays['p1Hand'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P1Hand.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  jarr := j.Arrays['p0Removed'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P0Removed.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  jarr := j.Arrays['p1Removed'];
  for i := 0 to jarr.Count - 1 do begin
    puz.P1Removed.Add(TCardJson.JsonToCard(jarr.Items[i]));
  end;

  puz.LPSelf := j.Integers['p0life'];
  puz.LPOpponent := j.Integers['p1life'];
  puz.Message := j.Strings['message'];
  puz.Solution := j.Strings['solution'];

  p.Free;
  j.Free;
  Exit(puz);
end;

function CardTypeToStr(ct: TCardType): String;
begin
  case ct of
  ctMonster: Exit('monster');
  ctSpell: Exit('spell');
  ctTrap: Exit('trap');
  ctPendulum: Exit('pendulum');
  end;
end;

function StrToCardType(str: String): TCardType;
begin
  if str = 'spell' then Exit(ctSpell)
  else if str = 'trap' then Exit(ctTrap)
  else if str = 'pendulum' then Exit(ctPendulum)
  else Exit(ctMonster);
end;

function CardLocationToStr(cl: TCardLocation): String;
begin
  case cl of
  clDeck: Exit('deck');
  clHand: Exit('hand');
  clGrave: Exit('grave');
  clRemoved: Exit('removed');
  clExtra: Exit('extra');
  clMZone: Exit('mzone');
  clSZone: Exit('szone');
  end;
end;

function StrToCardLocation(str: String): TCardLocation;
begin
  if str = 'hand' then Exit(clHand)
  else if str = 'grave' then Exit(clGrave)
  else if str = 'removed' then Exit(clRemoved)
  else if str = 'extra' then Exit(clExtra)
  else if str = 'mzone' then Exit(clMZone)
  else if str = 'szone' then Exit(clSZone)
  else Exit(clDeck);
end;

function CardOwnerToStr(co: TCardOwner): string;
begin
  case co of 
  coSelf: Exit('self');
  coOpponent: Exit('opponent');
  end;
end;

function StrToCardOwner(str: String): TCardOwner;
begin
  if str = 'self' then Exit(coSelf)
  else Exit(coOpponent);
end;

function CardPlayerToStr(cp: TCardPlayer): string;
begin
  case cp of
  cpSelf: Exit('self');
  cpOpponent: Exit('opponent');
  end;
end;

function StrToCardPlayer(str: String): TCardPlayer;
begin
  if str = 'self' then Exit(cpSelf)
  else Exit(cpOpponent);
end;

function CardPositionToStr(cp: TCardPosition): string;
begin
  case cp of
  cpUpAtk: Exit('upAtk');
  cpUpDef: Exit('upDef');
  cpDownDef: Exit('downDef');
  cpUp: Exit('up');
  cpDown: Exit('down');
  end;
end;

function StrToCardPosition(str: string): TCardPosition;
begin
  if str = 'upDef' then Exit(cpUpDef)
  else if str = 'downDef' then Exit(cpDownDef)
  else if str = 'up' then Exit(cpUp)
  else if str = 'down' then Exit(cpDown)
  else Exit(cpUpAtk);
end;

function CardWorkAsToStr(cwa: TCardWorkAs): string;
begin
  case cwa of
  waOrigin: Exit('none');
  waNormalMonster: Exit('nm');
  waEffectMonster: Exit('em');
  waRitualMonster: Exit('rm');
  waFusionMonster: Exit('fm');
  waSynchroMonster: Exit('sm');
  waXyzMonster: Exit('xm');
  waLinkMonster: Exit('lm');
  waPendulumMonster: Exit('pm');
  waToken: Exit('tm');
  waNormalSpell: Exit('ns');
  waEquipSpell: Exit('es');
  waFieldSpell: Exit('fs');
  waQuickPlaySpell: Exit('qs');
  waContinousSpell: Exit('cs');
  waRitualSpell: Exit('rs');
  waNormalTrap: Exit('nt');
  waContinousTrap: Exit('ct');
  waCounterTrap: Exit('c3t');
  end;
end;

function StrToCardWorkAs(str: string): TCardWorkAs;
begin
  if str = 'nm' then Exit(waNormalMonster)
  else if str = 'em' then Exit(waEffectMonster)
  else if str = 'rm' then Exit(waRitualMonster)
  else if str = 'fm' then Exit(waFusionMonster)
  else if str = 'sm' then Exit(waSynchroMonster)
  else if str = 'xm' then Exit(waXyzMonster)
  else if str = 'lm' then Exit(waLinkMonster)
  else if str = 'pm' then Exit(waPendulumMonster)
  else if str = 'tm' then Exit(waToken)
  else if str = 'ns' then Exit(waNormalSpell)
  else if str = 'es' then Exit(waEquipSpell)
  else if str = 'fs' then Exit(waFieldSpell)
  else if str = 'qs' then Exit(waQuickPlaySpell)
  else if str = 'cs' then Exit(waContinousSpell)
  else if str = 'rs' then Exit(waRitualSpell)
  else if str = 'nt' then Exit(waNormalTrap)
  else if str = 'ct' then Exit(waContinousTrap)
  else if str = 'c3t' then Exit(waCounterTrap)
  else Exit(waOrigin);
end;

end.

