unit untCardJson;

interface

uses
  Classes, SysUtils, JSON, untCard,System.Generics.Collections;

type
  TCardJson = class
  public
    class function CardToJson(ACard: ICard): TJSONValue;
    class function JsonToCard(AJson: TJSONValue): ICard;
  end;

  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

uses
  untArrayHelper;

{ TCardJson }

class function TCardJson.CardToJson(ACard: ICard): TJSONValue;
var
  json: TJSONObject;
  arr: TJSONArray;
  jsub: TJSONObject;
  i: Integer;
begin
  if ACard = nil then Exit(TJSONNull.Create);
  json := TJSONObject.Create();
  json.AddPair('cardId', ACard.GetCardId);
  json.AddPair('cardName', ACard.GetCardName);
  json.AddPair('cardType', CardTypeToStr(ACard.GetCardType));
  arr := TJSONArray.Create();
  for i := 0 to ACard.GetContinousEffectTo.Count - 1 do begin
    arr.Add(TJSONObject(TCardJson.CardToJson(ACard.GetContinousEffectTo[i])));
  end;
  json.AddPair('continousEffectTo', arr);
  json.AddPair('equipTo', TCardJson.CardToJson(ACard.GetEquipTo));
  json.AddPair('indicatorCount', ACard.GetIndicatorCount);
  json.AddPair('isLinkMonster', ACard.GetIsLinkMonster);
  json.AddPair('isXyzMonster', ACard.GetIsXyzMonster);
  json.AddPair('location', CardLocationToStr(ACard.GetLocation));
  json.AddPair('owner', CardOwnerToStr(ACard.GetOwner));
  json.AddPair('player', CardPlayerToStr(ACard.GetPlayer));
  json.AddPair('position', CardPositionToStr(ACard.GetPosition));
  json.AddPair('proc', ACard.GetProc);
  json.AddPair('seq', ACard.GetSeq);

  arr := TJSONArray.Create();
  for i := 0 to ACard.GetXyzElements.Count - 1 do begin
    arr.Add(ACard.GetXyzElements[i]);
  end;
  json.AddPair('xyzElements', arr);
  json.AddPair('workAs', CardWorkAsToStr(ACard.GetWorkAs));

  jsub := TJSONObject.Create;
  jsub.AddPair('useLevel', ACard.GetOverride.GetUseLevel);
  jsub.AddPair('useRank', ACard.GetOverride.GetUseRank);
  jsub.AddPair('useAttr', ACard.GetOverride.GetUseAttr);
  jsub.AddPair('useRace', ACard.GetOverride.GetUseRace);
  jsub.AddPair('useAtk', ACard.GetOverride.GetUseAtk);
  jsub.AddPair('useDef', ACard.GetOverride.GetUseDef);
  jsub.AddPair('level', ACard.GetOverride.GetLevel);
  jsub.AddPair('rank', ACard.GetOverride.GetRank);
  jsub.AddPair('attr', ACard.GetOverride.GetAttr);
  jsub.AddPair('race', ACard.GetOverride.GetRace);
  jsub.AddPair('atk', ACard.GetOverride.GetAtk);
  jsub.AddPair('def', ACard.GetOverride.GetDef);

  json.AddPair('override', jsub);

  Exit(json);
end;

class function TCardJson.JsonToCard(AJson: TJSONValue): ICard;
var
  jobj: TJSONObject;
  jsub: TJSONObject;
  arr: TJSONArray;
  c: ICard;
  co: ICardOverride;
  i: Integer;
  tmpArrCont: TArray<ICard>;
  tmpArrXyz: TArray<Int64>;
begin
  if AJson = nil then Exit(nil);
  if AJson.Null then Exit(nil);

  jobj := TJSONObject(AJson);
  c := TCard.Create;
  c.SetCardId(jobj.GetValue<Int64>('cardId'));
  c.setCardName(jobj.GetValue<String>('cardName'));
  c.SetCardType(StrToCardType(jobj.GetValue<String>('cardType')));
  arr := jobj.GetValue<TJSONArray>('continousEffectTo');
  SetLength(tmpArrCont, arr.Count);
  for i := 0 to arr.Count - 1 do begin
    tmpArrCont[i] := TCardJson.JsonToCard(arr[i]);
  end;
  c.SetContinousEffectTo(tmpArrCont);

  c.SetEquipTo(TCardJson.JsonToCard(jobj.GetValue<TJSONValue>('equipTo')));
  c.SetIndicatorCount(jobj.GetValue<Integer>('indicatorCount'));
  c.SetIsLinkMonster(jobj.GetValue<Boolean>('isLinkMonster'));
  c.SetIsXyzMonster(jobj.GetValue<Boolean>('isXyzMonster'));
  c.SetLocation(StrToCardLocation(jobj.GetValue<String>('location')));
  c.SetOwner(StrToCardOwner(jobj.GetValue<String>('owner')));
  c.SetPlayer(StrToCardPlayer(jobj.GetValue<String>('player')));
  c.SetPosition(StrToCardPosition(jobj.GetValue<string>('position')));
  c.SetProc(jobj.GetValue<Boolean>('proc'));
  c.SetSeq(jobj.GetValue<Integer>('seq'));
  arr := jobj.GetValue<TJSONArray>('xyzElements');

  SetLength(tmpArrXyz, arr.Count);
  for i := 0 to arr.Count - 1 do begin
    tmpArrXyz[i] := arr[i].AsType<Int64>;
  end;
  c.SetXyzElements(tmpArrXyz);

  c.SetWorkAs(StrToCardWorkAs(jobj.GetValue<String>('workAs')));

  jsub := jobj.GetValue<TJSONObject>('override');

  co := TCardOverride.Create;
  co.SetUseLevel(jsub.GetValue<Boolean>('useLevel'));
  co.SetUseRank(jsub.GetValue<Boolean>('useRank'));
  co.SetUseAttr(jsub.GetValue<Boolean>('useAttr'));
  co.SetUseRace(jsub.GetValue<Boolean>('useRace'));
  co.SetUseAtk(jsub.GetValue<Boolean>('useAtk'));
  co.SetUseDef(jsub.GetValue<Boolean>('useDef'));
  co.SetLevel(jsub.GetValue<Integer>('level'));
  co.SetRank(jsub.GetValue<Integer>('rank'));
  co.SetAttr(jsub.GetValue<Int64>('attr'));
  co.SetRace(jsub.GetValue<Int64>('race'));
  co.SetAtk(jsub.GetValue<Integer>('atk'));
  co.SetDef(jsub.GetValue<Integer>('def'));

  c.SetOverride(co);

  Exit(c);
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;

{ TPuzzleJson }

class function TPuzzleJson.JsonToPuzzle(AJsonString: String): TPuzzleField;
var
  puz: TPuzzleField;
  j: TJSONObject;
  jarr: TJSONArray;
  i: Integer;
begin
  j := TJSONObject(TJSONValue.ParseJSONValue(AJsonString, True));

  puz := TPuzzleField.Create;
  puz.PuzzleId := j.GetValue<Int64>('puzzleId');
  puz.PuzzleName := j.GetValue<String>('puzzleName');
  puz.AIName := j.GetValue<String>('aiName');
  for i := 0 to 4 do begin
    puz.MCard[0, i] := TCardJson.JsonToCard(j.GetValue<TJSONArray>('p0MCards')[i]);
  end;
  for i := 0 to 4 do begin
    puz.MCard[1, i] := TCardJson.JsonToCard(j.GetValue<TJSONArray>('p1MCards')[i]);
  end;
  for i := 0 to 5 do begin
    puz.SCard[0, i] := TCardJson.JsonToCard(j.GetValue<TJSONArray>('p0SCards')[i]);
  end;
  for i := 0 to 5 do begin
    puz.SCard[1, i] := TCardJson.JsonToCard(j.GetValue<TJSONArray>('p1SCards')[i]);
  end;
  for i := 5 to 6 do begin
    puz.ExtraMonster[i] := TCardJson.JsonToCard(j.GetValue<TJSONArray>('extraMonsters')[i - 5]);
  end;

  jarr := j.GetValue<TJSONArray>('p0Deck');
  for i := 0 to jarr.Count - 1 do begin
    puz.P0Deck.Add(TCardJson.JsonToCard(jarr[i]));
  end;

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

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

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

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

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

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

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

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

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

  puz.LPSelf := j.GetValue<Integer>('p0life');
  puz.LPOpponent := j.GetValue<Integer>('p1life');
  puz.Message := j.GetValue<String>('message');
  puz.Solution := j.GetValue<String>('solution');

  j.Free;
  Exit(puz);
end;

class function TPuzzleJson.PuzzleToJson(APuzzle: TPuzzleField): string;
var
  json: TJSONObject;
  jarr: TJSONArray;
  i: Integer;
  str: String;
begin
  json := TJSONObject.Create;
  json.AddPair('puzzleId', APuzzle.PuzzleId);
  json.AddPair('puzzleName', APuzzle.PuzzleName);
  json.AddPair('aiName', APuzzle.AIName);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  json.AddPair('p0life', APuzzle.LPSelf);
  json.AddPair('p1life', APuzzle.LPOpponent);
  json.AddPair('message', APuzzle.Message);
  json.AddPair('solution', APuzzle.Solution);
 
  str := json.ToJSON();
  json.free;
  Exit(str);
end;

end.
