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;
  }
}
