import {
  GroupConfigBlock,
  GroupConfigBlockFlags,
  GroupConfigBlockMemberFlags,
} from "./block";
import { GroupConfigBlockChain } from "./chain";

// Note: if you change this, update FlagParser.allPermission also
export interface MemberPermissions {
  isActive: boolean;
  isAdmin: boolean;
  canWriteDrive: boolean;
  canAdhocDrive: boolean;
  isModerator: boolean;
  canUploadDrive: boolean;
}

export interface RoomPermissions {
  allowAnonym?: boolean;
}

export class FlagParser {
  private membersPermissions: Map<string, MemberPermissions> = new Map<
    string,
    MemberPermissions
  >();

  // contains all permission with the negate pair
  public static allPermission: Object = {
    isActive: [
      GroupConfigBlockMemberFlags.ACTIVE,
      GroupConfigBlockMemberFlags.ACTIVE_NEGATE,
    ],
    isAdmin: [
      GroupConfigBlockMemberFlags.ADMINISTRATOR,
      GroupConfigBlockMemberFlags.ADMINISTRATOR_NEGATE,
    ],
    canWriteDrive: [
      GroupConfigBlockMemberFlags.DRIVE_WRITE,
      GroupConfigBlockMemberFlags.DRIVE_WRITE_NEGATE,
    ],
    canAdhocDrive: [
      GroupConfigBlockMemberFlags.DRIVE_ADHOC,
      GroupConfigBlockMemberFlags.DRIVE_ADHOC_NEGATE,
    ],
    canUploadDrive: [
      GroupConfigBlockMemberFlags.DRIVE_UPLOAD,
      GroupConfigBlockMemberFlags.DRIVE_UPLOAD_NEGATE,
    ]
  };

  private roomPermissions: RoomPermissions;

  public constructor(chain: GroupConfigBlockChain) {
    let state = chain.local_state_block();
    console.log("state", state["_M"]);
    let memberFlags = state[GroupConfigBlock.PROC_MEMBER_FLAGS];
    for (let key in memberFlags) {
      let obj = {};
      for (let attr in FlagParser.allPermission) {
        // set every permission
        obj[attr] = (memberFlags[key] & FlagParser.allPermission[attr][0]) != 0;
      }

      this.membersPermissions.set(key, <MemberPermissions>obj);
    }

    let groupFlags = state[GroupConfigBlock.PROC_GROUP_FLAGS];

    this.roomPermissions = {
      allowAnonym: (groupFlags & GroupConfigBlockFlags.ALLOW_ANONYMOUS) == 1,
    };
  }

  public static allFlag(): number{
    return GroupConfigBlockMemberFlags.ACTIVE |
    GroupConfigBlockMemberFlags.ADMINISTRATOR |
    GroupConfigBlockMemberFlags.DRIVE_ADHOC |
    GroupConfigBlockMemberFlags.DRIVE_WRITE |
    GroupConfigBlockMemberFlags.DRIVE_UPLOAD;
  }

  public static parseToFlags(
    oldP: MemberPermissions,
    newP: MemberPermissions
  ): number {

    // on default we need the active flag if its on
    let result = newP.isActive
      ? FlagParser.allPermission["isActive"][0]
      : FlagParser.allPermission["isActive"][1];

    // merge all flag if changed
    for (let attr in FlagParser.allPermission) {
      if (oldP[attr] != newP[attr]) {
        // change happened
        result |= newP[attr] // check if the value is pos/neg
          ? FlagParser.allPermission[attr][0] // merge the positive flag
          : FlagParser.allPermission[attr][1]; // merge the negative flag
      }
    }

    return result;
  }

  public getMembersPermissions(): Map<string, MemberPermissions> {
    return this.membersPermissions;
  }

  public getRoomPermissions(): RoomPermissions {
    return this.roomPermissions;
  }
}
