import { Injectable } from "@angular/core";
import { MeRecord } from "../server-services/query-records/account-records";
import {
  MessageRecord,
  RoomMyPermissionRecord,
  RoomRecord,
} from "../server-services/query-records/room-records";
import {
  WorkspaceQueryDialogueRecord,
  WorkspaceQueryRecord,
  WorkspaceQueryRoomRecord,
  WorkspaceQueryTimedOffers,
  WorkspaceSubscriptionDialogueMessageEventRecord,
  WorkspaceSubscriptionRecord,
  WorkspaceSubscriptionRoomMessageEventRecord,
} from "../server-services/query-records/workspace-records";
import {
  dialogueMessagesQuery,
  getAccountQuery,
  getAllAccountIdQuery,
  getAllRoomQuery,
  getContactListQuery,
  getDialogueDataQuery,
  getMeQuery,
  getNanoLicensesQuery,
  getRoomDataQuery,
  getTimedOffersQuery,
  getVersionQuery,
  Query,
  roomMessagesQuery,
  roomMyPermissionsQuery,
  roomPermissionsQuery,
  waitingNanosQuery,
} from "../server-services/querys";
import {
  SubscriptionServiceEvent,
  SubscriptionServiceEventType,
} from "../server-services/subscription-event";
import { marker } from "@biesbjerg/ngx-translate-extract-marker";
import { RoomData } from "../server-services/room.service";
import { ResourceType } from "src/app/components/resources-sidebar/sidebar-data";
import { AccountAvatarRecord } from "../../shared/server-services/query-records/account-records";
import { DialogueDataRecord } from "../../shared/server-services/query-records/room-records";
import {
  TimedOfferRecord,
  TimedOfferData,
} from "../server-services/query-records/timed-offer-records";

export let cacheCustomLogic: CacheLogic = {
  makeCacheKey: function (query: Query, variables = {}) {
    let id;
    let endpoint = query.endpoint;

    switch (query.endpoint) {
      case "roomMessages":
        id = variables.roomId;
        break;
      case "dialogueMessages":
        id = variables.peerId;
        break;
      case "allAccount":
        id = "";
        break;
      default:
        id = variables.id ? variables.id : "";
        break;
    }

    return (query.operation ? query.operation : "") + "." + endpoint + "." + id;
  },

  conditionForQueryFetch: {
    default: function (cacheKey, query, variables, cache: CacheService) {
      return cache.get(cacheKey) === undefined;
    },
    roomMessages: function (cacheKey, query, variables, cache: CacheService) {
      return variables.pivot != null || cache.get(cacheKey) === undefined;
    },
    dialogueData: function (cacheKey, query, variables, cache: CacheService) {
      return false;
    },
    timedOffers: function (cacheKey, query, variables, cache: CacheService) {
      return false;
    },
    allRoom: function (cacheKey, query, variables, cache: CacheService) {
      return false;
    },
    dialogueMessages: function (
      cacheKey,
      query,
      variables,
      cache: CacheService
    ) {
      return variables.pivot != null || cache.get(cacheKey) === undefined;
    },
    nanoRequest: function (cacheKey, query, variables, cache: CacheService) {
      return true;
    },
    twoFactor: function (cacheKey, query, variables, cache: CacheService) {
      return true;
    },
    nanoSlots: function (cacheKey, query, variables, cache: CacheService) {
      return true;
    },

    // we don't have live events for these, so have to refresh every time
    roomPermissions: function (
      cacheKey,
      query,
      variables,
      cache: CacheService
    ) {
      return true;
    },
    roomMembers: function (cacheKey, query, variables, cache: CacheService) {
      return true;
    },
    roomConfig: function (cacheKey, query, variables, cache: CacheService) {
      return true;
    },
    allAccountId: function (cacheKey, query, variables, cache: CacheService) {
      return false;
    },
    nanoLicensesV2: function (cacheKey, query, variables, cache: CacheService){
      return true;
    },
    paymentBillings: function (cacheKey, query, variables, cache: CacheService){
      return true;
    },
    paymentParseBack: function (cacheKey, query, variables, cache: CacheService){
      return true;
    },
    paymentRecurringOrders: function (cacheKey, query, variables, cache: CacheService){
      return true;
    },
    nanoLicenseBundleTokens: function (cacheKey, query, variables, cache: CacheService){
      return true;
    },
    loginSessions: function (cacheKey, query, variables, cache: CacheService) {
      return true;
    },
    aggregateStats: function (cacheKey, query, variables, cache: CacheService) {
      return true;
    },
    nanoMetrics: function (cacheKey, query, variables, cache: CacheService) {
      return true;
    },
  },

  merge: {
    query: {
      default: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) {
        cache.set(cacheKey, response);
      },
      roomMessages: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) {
        /*if (variables.pivot == null) {
          cache.set(cacheKey, response);
        } else {
          cache.set(cacheKey, cache.get(cacheKey).concat(response));
        }*/
        let message = cache.get(cacheKey);
        if (message) {
          cache.set(cacheKey, message.concat(response));
        } else {
          cache.set(cacheKey, response);
        }
      },
      dialogueMessages: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) {
        let message = cache.get(cacheKey);
        if (message) {
          cache.set(cacheKey, message.concat(response));
        } else {
          cache.set(cacheKey, response);
        }
      },
      workspace: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response: WorkspaceQueryRecord
      ) {
        cache.set(getAllAccountIdQuery, []);
        cache.set(getAllRoomQuery, []);

        let allResource: (
          | WorkspaceQueryRoomRecord
          | WorkspaceQueryDialogueRecord
        )[] = [];

        response.resourceGroups.forEach((group) => {
          allResource = allResource.concat(group.resources);
        });
        allResource = allResource.concat(response.ungroupedResources);
        // should we collect the rejected and granted rooms too?

        allResource.forEach((resource) => {
          if (resource.type == ResourceType.ROOM) {
            cache.set(getRoomDataQuery, resource, resource);
            cache.get(getAllRoomQuery).push(resource);
          } else {
            cache.set(getDialogueDataQuery, resource, resource);
            cache.get(getAllAccountIdQuery).push(resource.id);
          }
        });

        cache.set(waitingNanosQuery, response.waitingNanos);
        cache.set(getMeQuery, response.me);
        cache.set(getContactListQuery, response.contactAvatars);
        cache.set(getVersionQuery, response.newestNano)

        cache.set(getAccountQuery, { id: response.me.id }, response.me);

        for (let i = 0; i < response.contactAvatars.length; i++) {
          cache.set(
            getAccountQuery,
            { id: response.contactAvatars[i].id },
            response.contactAvatars[i]
          );
          let allAccountId = cache.get(getAllAccountIdQuery);
          if (!allAccountId.includes(response.contactAvatars[i].id)) {
            cache.get(getAllAccountIdQuery).push(response.contactAvatars[i].id);
          }
        }

        cache.set(getTimedOffersQuery, response.timedOffers);
        
        cache.set(cacheKey, response);
      },
      nanoRequest: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) {},
      roomData: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) {
        cache.set(cacheKey, response);
        if (response["pinnedKey"] || response["public"]) {
          // only the joined rooms
          cache.get(getAllRoomQuery).push(response);
        }
      },
    },
    mutation: {
      default: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) {},
      joinRoom: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) {
        // it should be there
        let room = cache.get(getRoomDataQuery, { id: variables["roomId"] });

        if (room) {
          cache.get(getAllRoomQuery).push(room);
        } else {
          throw "Can not find room in the cache";
        }
      },
      leaveRoom: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) {
        let allRoom = cache.get(getAllRoomQuery);
        for (let i = 0; i < allRoom.length; i++) {
          if (allRoom[i]["id"] == variables["roomId"]) {
            allRoom.splice(i, 1);
            return;
          }
        }
      }
    },
    subscription: {
      default: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) {},
      workspaceChanges: function (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response: WorkspaceSubscriptionRecord
      ) {
        if (response[SubscriptionServiceEvent.ROOM_MESSAGE_EVENT]) {
          let roomMessageEvent: WorkspaceSubscriptionRoomMessageEventRecord =
            response[SubscriptionServiceEvent.ROOM_MESSAGE_EVENT];
          let messages = cache.get(roomMessagesQuery, {
            roomId: roomMessageEvent.id,
          });

          if (!messages) {
            messages = [];
            cache.set(
              roomMessagesQuery,
              {
                roomId: roomMessageEvent.id,
              },
              messages
            );
          }

          switch (roomMessageEvent.cmd) {
            // message created
            case SubscriptionServiceEventType.CREATE:
              let msg: MessageRecord = {
                id: roomMessageEvent.messageId,
                posterId: roomMessageEvent.posterId,
                content: <string>roomMessageEvent.content,
                edited: roomMessageEvent.edited,
              };

              messages.unshift(msg);
              break;
            // message modification
            case SubscriptionServiceEventType.MODIFY:
              for (let i = 0; i < messages.length; i++) {
                if (messages[i].id == roomMessageEvent.messageId) {
                  messages[i].content = roomMessageEvent.content;
                  break;
                }
              }
              break;
            // message deleted
            case SubscriptionServiceEventType.DELETE:
              for (let i = 0; i < messages.length; i++) {
                if (messages[i].id == roomMessageEvent.messageId) {
                  messages.splice(i, 1);
                  break;
                }
              }
              break;
          }
        }

        if (response[SubscriptionServiceEvent.DIALOGUE_MESSAGE_EVENT]) {
          let dialogueMessageEvent: WorkspaceSubscriptionDialogueMessageEventRecord =
            response[SubscriptionServiceEvent.DIALOGUE_MESSAGE_EVENT];
          let messages = cache.get(dialogueMessagesQuery, {
            peerId: dialogueMessageEvent.id,
          });

          if (!messages) {
            messages = [];
            cache.set(
              dialogueMessagesQuery,
              {
                peerId: dialogueMessageEvent.id,
              },
              messages
            );
          }

          switch (dialogueMessageEvent.cmd) {
            // message created
            case SubscriptionServiceEventType.CREATE:
              let msg: MessageRecord = {
                id: dialogueMessageEvent.messageId,
                posterId: dialogueMessageEvent.posterId,
                content: <string>dialogueMessageEvent.content,
                edited: dialogueMessageEvent.edited,
              };

              messages.unshift(msg);
              break;
            // message modification
            case SubscriptionServiceEventType.MODIFY:
              for (let i = 0; i < messages.length; i++) {
                if (messages[i].id == dialogueMessageEvent.messageId) {
                  messages[i].content = dialogueMessageEvent.content;
                  break;
                }
              }
              break;
            // message deleted
            case SubscriptionServiceEventType.DELETE:
              for (let i = 0; i < messages.length; i++) {
                if (messages[i].id == dialogueMessageEvent.messageId) {
                  messages.splice(i, 1);
                  break;
                }
              }
              break;
          }
        }

        if (SubscriptionServiceEvent.ROOM_EVENT in response) {
          let roomEvent = response[SubscriptionServiceEvent.ROOM_EVENT];
          
          if (
            response[SubscriptionServiceEvent.ROOM_EVENT].cmd ==
            SubscriptionServiceEventType.MODIFY
          ) {
            let room: RoomRecord = cache.get(getRoomDataQuery, { id: roomEvent.id });
            // seen subscriptption does not contain data
            if (room) {
              if (roomEvent.data){
                room.data = roomEvent.data;
              }
              if (roomEvent.seenMessageId){
                room.seenMessageId = roomEvent.seenMessageId;
              }
              if (roomEvent.topMessageId){
                room.topMessageId = roomEvent.topMessageId;
              }
              if (roomEvent.error != undefined){
                room.error = roomEvent.error;
                room.errorMessage = roomEvent.errorMessage;
              }
              if (roomEvent.nanoSessionsAdded){
                room.nanoSessions = Object.assign(room.nanoSessions, roomEvent.nanoSessionsAdded);
              }
              if (roomEvent.nanoSessionsRemoved){
                roomEvent.nanoSessionsRemoved.forEach(element => {
                  delete room.nanoSessions[element];
                });
              }
              if (roomEvent.nanoSessionsReset){
                room.nanoSessions = roomEvent.nanoSessionsReset;
              }
            }
          }
          if (
            response[SubscriptionServiceEvent.ROOM_EVENT].cmd ==
            SubscriptionServiceEventType.DELETE
          ) {
            let rooms: RoomRecord[] = cache.get(getAllRoomQuery);
            for (let i = 0; i < rooms.length; i++) {
              if (rooms[i].id == roomEvent.id) {
                rooms.splice(i, 1);
                break;
              }
            }
          }
        }

        if (SubscriptionServiceEvent.DIALOGUE_EVENT in response) {
          let dialogueEvent = response[SubscriptionServiceEvent.DIALOGUE_EVENT];

          if (
            response[SubscriptionServiceEvent.DIALOGUE_EVENT].cmd ==
            SubscriptionServiceEventType.CREATE
          ) {
            if (!cache.get(getDialogueDataQuery, { id: dialogueEvent.id })) {
              let dialogueData: DialogueDataRecord = {
                error: false,
                hidden: null,
                id: dialogueEvent.id,
                ignore: null,
                ordering: -1,
                seenMessageId: null,
                topMessageId: null,
                type: ResourceType.DIALOGUE,
                account: cache.get(getAccountQuery, { id: dialogueEvent.id }),
              };

              cache.set(
                getDialogueDataQuery,
                { id: dialogueEvent.id },
                dialogueData
              );
            }
          }
          else if (
            response[SubscriptionServiceEvent.DIALOGUE_EVENT].cmd ==
            SubscriptionServiceEventType.MODIFY
          ) {
            let dialogueData = cache.get(getDialogueDataQuery, { id: dialogueEvent.id });

            if (dialogueData){
              if (dialogueEvent.seenMessageId){
                dialogueData.seenMessageId = dialogueEvent.seenMessageId;
              }
              if (dialogueEvent.topMessageId){
                dialogueData.topMessageId = dialogueEvent.topMessageId;
              }
            }
          }
        }

        if (SubscriptionServiceEvent.NANO_WAITING_EVENT in response) {
          let waitingEvent =
            response[SubscriptionServiceEvent.NANO_WAITING_EVENT];

          if (waitingEvent.cmd == SubscriptionServiceEventType.CREATE) {
            cache.get(waitingNanosQuery)[waitingEvent.waiterId] =
              waitingEvent.aliveUntil;
          } else if (waitingEvent.cmd == SubscriptionServiceEventType.DELETE) {
            delete cache.get(waitingNanosQuery)[waitingEvent.waiterId];
          }
        }

        if (SubscriptionServiceEvent.ROOM_PERMISSION_EVENT in response) {
          let permEvent =
            response[SubscriptionServiceEvent.ROOM_PERMISSION_EVENT];

          // it affects only the room permissions
          if (permEvent.cmd == SubscriptionServiceEventType.MODIFY) {
            //console.log("perm M", response);
          } else if (permEvent.cmd == SubscriptionServiceEventType.DELETE) {
            let room: RoomRecord = cache.get(getRoomDataQuery, {
              id: permEvent.id,
            });
            room.error = true;
            // deleted room, we can let it like this
            room.errorMessage = marker("Not available");
          }
        }

        if (
          SubscriptionServiceEvent.ROOM_ACCOUNT_PERMISSION_EVENT in response
        ) {
          let accPermEvent =
            response[SubscriptionServiceEvent.ROOM_ACCOUNT_PERMISSION_EVENT];
          console.log('perm event', accPermEvent)
          if ((<MeRecord>cache.get(getMeQuery)).id == accPermEvent.accountId) {
            let room: RoomRecord = cache.get(getRoomDataQuery, {
              id: accPermEvent.id,
            });
            if (room) {
              if (accPermEvent.cmd == SubscriptionServiceEventType.DELETE) {
                room.error = true;
                room.errorMessage = marker("Not available"); // TODO this can override the prev error

                let perm: RoomMyPermissionRecord = cache.get(
                  roomMyPermissionsQuery,
                  { id: accPermEvent.id }
                );

                if (perm) {
                  perm.account.administrator = false;
                  perm.account.driveAdhoc = false;
                  perm.account.driveWrite = false;
                  perm.account.msgBrdModerate = false;
                  perm.account.driveUpload = false;
                } // else just wait for the first query
              } else {
                if (accPermEvent.cmd == SubscriptionServiceEventType.CREATE) {
                  if ((<RoomData>room.data)?.name) {
                    room.error = false;
                  } else {
                    room.error = true;
                    room.errorMessage = marker("Decryption error"); // TODO it can be Dataset or Decryption error to
                  }
                }

                // CREATE && MODIFY
                let perm: RoomMyPermissionRecord = cache.get(
                  roomMyPermissionsQuery,
                  { id: accPermEvent.id }
                );

                if (perm) {
                  perm.account.administrator = accPermEvent.administrator;
                  perm.account.driveAdhoc = accPermEvent.driveAdhoc;
                  perm.account.driveWrite = accPermEvent.driveWrite;
                  perm.account.msgBrdModerate = accPermEvent.msgBrdModerate;
                  perm.account.driveUpload = accPermEvent.driveUpload;
                } // else just wait for the first query
              }
            }
          }
        }

        if (SubscriptionServiceEvent.ACCOUNT_CONTACT_EVENT in response) {
          let accContactEvent =
            response[SubscriptionServiceEvent.ACCOUNT_CONTACT_EVENT];
          let contactList: AccountAvatarRecord[] =
            cache.get(getContactListQuery);

          if (accContactEvent.cmd == SubscriptionServiceEventType.CREATE) {
            // TODO what if this is not in the cache
            let acc: AccountAvatarRecord = cache.get(getAccountQuery, {
              id: accContactEvent.peerId,
            });
            if (!contactList.includes(acc)) {
              contactList.push(acc);
            }

            let allAcc: string[] = cache.get(getAllAccountIdQuery);

            let found = false;
            for (let i = 0; i < allAcc.length; i++) {
              if (allAcc[i] == acc.id) {
                found = true;
                break;
              }
            }
            if (!found) {
              allAcc.push(acc.id);
            }
          } else if (
            accContactEvent.cmd == SubscriptionServiceEventType.DELETE
          ) {
            for (let i = 0; i < contactList.length; i++) {
              if (contactList[i].id == accContactEvent.peerId) {
                contactList.splice(i, 1);
                break;
              }
            }
          }
        }

        if (SubscriptionServiceEvent.ACCOUNT_OFFER_EVENT in response) {
          let accOfferEvent =
            response[SubscriptionServiceEvent.ACCOUNT_OFFER_EVENT];

          let allAccountOffer: TimedOfferRecord[] =
            cache.get(getTimedOffersQuery);

          if (accOfferEvent.cmd == SubscriptionServiceEventType.DELETE) {
            for (let i = 0; i < allAccountOffer.length; i++) {
              if (allAccountOffer[i].id == accOfferEvent.id) {
                allAccountOffer.splice(i, 1);
                break;
              }
            }
            cache.delete(getNanoLicensesQuery);
          } else if (accOfferEvent.cmd == SubscriptionServiceEventType.CREATE) {
            allAccountOffer.push({
              id: accOfferEvent.id,
              data: <TimedOfferData>accOfferEvent.data,
              expiration: accOfferEvent.expiration,
            });
          }
        }

        if (SubscriptionServiceEvent.ACCOUNT_EVENT in response) {
          let accountEvent = response[SubscriptionServiceEvent.ACCOUNT_EVENT];
          let user: AccountAvatarRecord = cache.get(getAccountQuery, {
            id: accountEvent.id,
          });

          let me: MeRecord = cache.get(getMeQuery);

          if (accountEvent.avatarImageKey) {
            user.avatarImageKey = accountEvent.avatarImageKey;
            if (me.id == user.id) {
              me.avatarImageKey = accountEvent.avatarImageKey;
            }
          }
          if (accountEvent.avatarName) {
            user.avatarName = accountEvent.avatarName;
            if (me.id == user.id) {
              me.avatarName = accountEvent.avatarName;
            }
          }
        }
      },
    },
  },
};

interface CacheLogic {
  makeCacheKey: (query: Query, variables?) => string;
  conditionForQueryFetch: {
    [key: string]: (cacheKey, query, variables, cache: CacheService) => boolean;
  };
  merge: {
    query: {
      [key: string]: (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) => void;
    };
    mutation: {
      [key: string]: (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) => void;
    };
    subscription: {
      [key: string]: (
        cacheKey,
        query,
        variables,
        cache: CacheService,
        response
      ) => void;
    };
  };
}

@Injectable({
  providedIn: "root",
})
export class CacheService {
  cacheData;
  public resetCache() {
    this.cacheData = {
      [this.cacheLogic.makeCacheKey(getAllRoomQuery)]: [],
      [this.cacheLogic.makeCacheKey(getAllAccountIdQuery)]: [],
      [this.cacheLogic.makeCacheKey(getContactListQuery)]: [],
      [this.cacheLogic.makeCacheKey(getTimedOffersQuery)]: [],
    };
  }

  markedCacheDatasForUpdate = [];

  cacheLogic: CacheLogic;

  constructor() {
    this.cacheLogic = cacheCustomLogic; // TODO pass it nicely
    this.resetCache();
  }

  /**
   * syncronize a request with the cache
   * @param request outcoming query request to the server, it must be stored in the runningQuerys
   * @param response incoming query result from the server
   */
  public mergeQueryResult(query: Query, variables, response) {
    let cacheKey = this.cacheLogic.makeCacheKey(query, variables);

    if (query.endpoint in this.cacheLogic.merge[query.operation]) {
      this.cacheLogic.merge[query.operation][query.endpoint](
        cacheKey,
        query,
        variables,
        this,
        response
      );
    } else {
      this.cacheLogic.merge[query.operation]["default"](
        cacheKey,
        query,
        variables,
        this,
        response
      );
    }
  }

  /**
   * If the result of the query already in the cache, we dont have to refetch it.
   * If the data is not in the cache or is in the cache but marked for update,
   * we have to start a server request for it
   * @param query
   * @param variables
   * @return {boolean} true - if query result already in the cache, false if it is not in the cache, or marked for update
   */
  public isDataNeedToBeUpdated(cacheKey: string, query: Query, variables) {
    if (query.endpoint in this.cacheLogic.conditionForQueryFetch) {
      return this.cacheLogic.conditionForQueryFetch[query.endpoint](
        cacheKey,
        query,
        variables,
        this
      );
    } else {
      return this.cacheLogic.conditionForQueryFetch["default"](
        cacheKey,
        query,
        variables,
        this
      );
    }

    //let cache = this.getCachedData(requestKey, query, variables);

    // there is no cached data or we need to update it
    //return (cache === undefined /*|| this.isDataMarkedForUpdate(requestKey)*/);
  }

  /*
  private isDataMarkedForUpdate(requestKey){
    return this.markedCacheDatasForUpdate.includes(requestKey);
  }

  private markDataForUpdate(requestKey){
    if (!this.markedCacheDatasForUpdate.includes(requestKey)){
      this.markedCacheDatasForUpdate.push(requestKey);
    }
  }

  private unmarkDataForUpdate(requestKey){
    let index = this.markedCacheDatasForUpdate.indexOf(requestKey);
    if (index > -1){
      this.markedCacheDatasForUpdate.splice(index, 1);
    } 
    
  }
  */

  /**
   * Get the reference of the cached data for the query
   */
  public get(cacheKey: string): any;
  public get(query: Query, variables?: Object): any;
  public get(key: Query | string, variables: Object = {}): any {
    if (typeof key == "string") {
      return this.cacheData[key];
    } else {
      if (!key.operation) {
        console.error("Operation missing on query", key);
      }
      return this.cacheData[this.cacheLogic.makeCacheKey(key, variables)];
    }
  }

  public delete(query: Query, variables: Object = {}) {
    delete this.cacheData[this.cacheLogic.makeCacheKey(query, variables)];
  }

  public set(cacheKey: string, data: any): void;
  public set(query: Query, data: any): void;
  public set(query: Query, variables: Object, data: any): void;
  public set(a: Query | string, b: Object | any, c?: any): void {
    if (typeof a == "string") {
      this.cacheData[a] = b;
    } else {
      if (c !== undefined) {
        this.cacheData[this.cacheLogic.makeCacheKey(a, b)] = c;
      } else {
        this.cacheData[this.cacheLogic.makeCacheKey(a, {})] = b;
      }
    }
  }
}
