import * as _ from 'lodash';

const ACC_PUBLIC = 0x0001;
const ACC_PRIVATE = 0x0002;
const ACC_PROTECTED = 0x0004;
const ACC_STATIC = 0x0008;
const ACC_FINAL = 0x0010;
const ACC_SUPER = 0x0020; // ClassInfo only
const ACC_SYNCHRONIZED = 0x0020;
const ACC_VOLATILE = 0x0040;
const ACC_BRIDGE = 0x0040;
const ACC_TRANSIENT = 0x0080;
const ACC_VARARGS = 0x0080;
const ACC_NATIVE = 0x100;
const ACC_INTERFACE = 0x0200;
const ACC_ABSTRACT = 0x0400;
const ACC_STRICT = 0x0800;
const ACC_SYNTHETIC = 0x1000;
const ACC_ANNOTATION = 0x2000;
const ACC_ENUM = 0x4000;

const FLAGS = {
  ACC_PUBLIC,
  ACC_PRIVATE,
  ACC_PROTECTED,
  ACC_STATIC,
  ACC_FINAL,
  ACC_SUPER,
  ACC_SYNCHRONIZED,
  ACC_VOLATILE,
  ACC_BRIDGE,
  ACC_TRANSIENT,
  ACC_VARARGS,
  ACC_NATIVE,
  ACC_INTERFACE,
  ACC_ABSTRACT,
  ACC_STRICT,
  ACC_SYNTHETIC,
  ACC_ANNOTATION,
  ACC_ENUM
};

/**
 * [AccessFlags description]
 */
function AccessFlags() {
  let funcs = {};
  
  _.each(FLAGS, (val, key) => {
    let name = key.split('_')[1].toLowerCase();
    let methodName = 'is' + (name[0].toUpperCase()) + name.substring(1);

    funcs[methodName] = function (flag) {
      return (val & flag) !== 0;
    };
  });

  funcs.listFlags = (flags) => {
      // console.log(funcs)
    return _.pluck(_.filter(_.map(_.keys(funcs), (method) => {
      if (!method.startsWith('is')) {
        return null;
      }
      // console.log(method)
      let name = method.substring(2).toLowerCase();
      return {
        test: ACCESS_FLAGS[method](flags),
        name: name
      }
    }), { test: true }), 'name');
  }

  return funcs;
}

const ACCESS_FLAGS = new AccessFlags();

/** @type {AccessFlags} */
let Flags = ACCESS_FLAGS;

export {
  Flags,
  ACC_PUBLIC,
  ACC_PRIVATE,
  ACC_PROTECTED,
  ACC_STATIC,
  ACC_FINAL,
  ACC_SUPER,
  ACC_SYNCHRONIZED,
  ACC_VOLATILE,
  ACC_BRIDGE,
  ACC_TRANSIENT,
  ACC_VARARGS,
  ACC_NATIVE,
  ACC_INTERFACE,
  ACC_ABSTRACT,
  ACC_STRICT,
  ACC_SYNTHETIC,
  ACC_ANNOTATION,
  ACC_ENUM
}

@@ -850,99 +850,49 @@
 %7D;%0A%0A
-/**%0A * %5BAccessFlags description%5D%0A */%0Afunction AccessFlags() %7B%0A  let funcs = %7B%7D;%0A  %0A  _.each
+export const MethodNames = _.object(_.map
 (FLA
@@ -967,24 +967,20 @@
     
-let methodName =
+return %5Bval,
  'is
@@ -1030,70 +1030,133 @@
 g(1)
-;%0A%0A    funcs%5BmethodName%5D = function (flag) %7B%0A      return (val
+%5D;%0A%7D));%0A%0Aexport const FlagMethods = _.object(_.map(MethodNames, (methodName, mask) =%3E %7B%0A  return %5BmethodName, (flag) =%3E (mask
  & f
@@ -1169,84 +1169,148 @@
 == 0
+%5D
 ;%0A
-    %7D;%0A  %7D);%0A%0A  funcs.listFlags = (flags) =%3E %7B%0A      // console.log(funcs)
+%7D));%0A%0A/**%0A * %5BAccessFlags description%5D%0A */%0Afunction AccessFlags() %7B%0A  let funcs = _.clone(FlagMethods);%0A%0A  funcs.listFlags = (flags) =%3E %7B
 %0A   
@@ -1321,16 +1321,8 @@
 urn 
-_.pluck(
 _.fi
@@ -1336,301 +1336,120 @@
 map(
-_.keys(funcs), (method) =%3E %7B%0A      if (!method.startsWith('is')) %7B%0A        return null;%0A      %7D%0A      // console.log(method)%0A      let name = method.substring(2).toLowerCase();%0A      return %7B%0A        test: ACCESS_FLAGS%5Bmethod%5D(flags),%0A        name: name%0A      %7D%0A    %7D), %7B test: true %7D), 'name'
+FlagMethods, (maskFunc, name) =%3E %7B%0A      return maskFunc(flags) ? name.substring(2).toLowerCase() : null;%0A    %7D)
 );%0A 

refactor AccessFlags to support code reuse