/*

 * Copyright (c) 2021 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



const fs = require('fs');

const path = require('path');

import ts from 'typescript';

import {

  WHITELISTNEW,

  readExternalComponents

} from './external_component_map';

const COMPONENTS = 'components';

const FORM_COMPONENTS = 'form_components';

export const COMPONENT_MAP: any = {};

export const FORM_MAP: any = {};



let EXTERNAL_COMPONENT_MAP: object = {};

export let EXT_WHITE_LIST: Array<string> = [];

export let COMMON_ATTRS: Set<string> = new Set([]);



(function readComponents(): void {

  EXTERNAL_COMPONENT_MAP = readExternalComponents();

  EXT_WHITE_LIST = WHITELISTNEW;

  const componentPath: Map<string, string> = new Map([

    [`${COMPONENTS}`, `../${COMPONENTS}`],

    [`${FORM_COMPONENTS}`, `../${FORM_COMPONENTS}`]

  ]);

  for (const [id, relPath] of componentPath.entries()) {

    const componentsFile: string = path.join(__dirname, relPath);

    const files: string[] = fs.readdirSync(componentsFile);

    files.forEach(function (item) {

      const fPath: string = path.join(componentsFile, item);

      const json: any = require(fPath);

      const stat: any = fs.statSync(fPath);

      if (stat.isFile()) {

        if (json.name) {

          const compName: string = json.name;

          delete json.name;

          if (id === COMPONENTS) {

            COMPONENT_MAP[compName] = json;

          } else if (id === FORM_COMPONENTS) {

            FORM_MAP[compName] = json;

          }

        } else {

          if (id === COMPONENTS) {

            COMMON_ATTRS = new Set(json.attrs);

          }

        }

      }

    });

  }

  addExternalComponents();

})();



function addExternalComponents(): void {

  const componentMapKeys = new Set(Object.keys(COMPONENT_MAP));

  const extComponentSet: Set<string> = new Set(EXTERNAL_COMPONENT_MAP ?

    Object.keys(EXTERNAL_COMPONENT_MAP) : []);

  const extComponentKeys: Array<string> = Array.from(extComponentSet);

  if (!extComponentKeys.length) {

    return;

  }

  extComponentKeys.forEach((extCompName: string) => {

    if (componentMapKeys.has(extCompName) && COMPONENT_MAP[extCompName].parents &&

      EXTERNAL_COMPONENT_MAP[extCompName].parents) {

      const newParents: Array<string> = Array.from(new Set([...COMPONENT_MAP[extCompName].parents,

      ...EXTERNAL_COMPONENT_MAP[extCompName].parents]));

      COMPONENT_MAP[extCompName].parents = newParents;

    } else {

      COMPONENT_MAP[extCompName] = EXTERNAL_COMPONENT_MAP[extCompName];

    }

  });

}



export const TRANSITION_COMMON_ATTRS: Set<string> = new Set([

  'slide', 'translate', 'scale', 'opacity'

]);

export const GESTURE_ATTRS: Set<string> = new Set([

  'gesture', 'parallelGesture', 'priorityGesture'

]);



export const ID_ATTRS: Map<string, Map<string, string | number>> = new Map();



export const forbiddenUseStateType: Set<string> = new Set(['Scroller', 'SwiperScroller',

  'VideoController', 'WebController', 'CustomDialogController', 'SwiperController',

  'TabsController', 'CalendarController', 'AbilityController', 'XComponentController',

  'CanvasRenderingContext2D', 'CanvasGradient', 'ImageBitmap', 'ImageData', 'Path2D',

  'RenderingContextSettings', 'OffscreenCanvasRenderingContext2D', 'PatternLockController',

  'TextAreaController', 'TextInputController', 'TextTimerController', 'SearchController', 'RichEditorController',

  'ArcSwiperController'

]);



export const FOREACH_ATTRIBUTE = ['onMove'];

export const INNER_COMPONENT_NAMES: Set<string> = new Set();

export const NO_DEBUG_LINE_COMPONENT: Set<string> = new Set();

export const BUILDIN_CONTAINER_COMPONENT: Set<string> = new Set();

export const COMPONENT_SYSTEMAPI_NAMES: Set<string> = new Set();

export const BUILDIN_STYLE_NAMES: Set<string> = new Set([

  ...COMMON_ATTRS, ...GESTURE_ATTRS, ...TRANSITION_COMMON_ATTRS, ...FOREACH_ATTRIBUTE

]);

export const AUTOMIC_COMPONENT: Set<string> = new Set();

export const SINGLE_CHILD_COMPONENT: Set<string> = new Set();

export const SPECIFIC_CHILD_COMPONENT: Map<string, Set<string>> = new Map();

export const SPECIFIC_PARENT_COMPONENT: Map<string, Set<string>> = new Map();

export const GESTURE_TYPE_NAMES: Set<string> = new Set([

  'TapGesture', 'LongPressGesture', 'PanGesture', 'PinchGesture', 'RotationGesture', 'GestureGroup',

  'SwipeGesture'

]);

export const CUSTOM_BUILDER_METHOD: Set<string> = new Set();

export const INNER_CUSTOM_LOCALBUILDER_METHOD: Set<string> = new Set();

export const INNER_STYLE_FUNCTION: Map<string, ts.Block> = new Map();

export const GLOBAL_STYLE_FUNCTION: Map<string, ts.Block> = new Map();



export interface ExtendParamterInterfance {

  attribute: string,

  parameterCount: number

}

export const EXTEND_ATTRIBUTE: Map<string, Set<string>> = new Map();

export const STYLES_ATTRIBUTE: Set<string> = new Set();



export const INTERFACE_NODE_SET: Set<ts.InterfaceDeclaration> = new Set();



export const INNER_CUSTOM_BUILDER_METHOD: Set<string> = new Set();

export const GLOBAL_CUSTOM_BUILDER_METHOD: Set<string> = new Set();



export const JS_BIND_COMPONENTS: Set<string> = new Set([

  'ForEach', 'LazyForEach', ...GESTURE_TYPE_NAMES, 'Gesture',

  'PanGestureOption', 'CustomDialogController', 'Storage', 'Scroller', 'SwiperController',

  'TabsController', 'CalendarController', 'AbilityController', 'VideoController', 'WebController',

  'XComponentController', 'CanvasRenderingContext2D', 'CanvasGradient', 'ImageBitmap', 'ImageData',

  'Path2D', 'RenderingContextSettings', 'OffscreenCanvasRenderingContext2D', 'DatePickerDialog',

  'TextPickerDialog', 'AlertDialog', 'ContextMenu', 'ActionSheet', 'PatternLockController',

  'TimePickerDialog', 'CalendarPickerDialog', 'ArcSwiperController'

]);



export const NEEDPOP_COMPONENT: Set<string> = new Set(['Blank', 'Search']);



export const CUSTOM_BUILDER_PROPERTIES: Set<string> = new Set(['background', 'bindPopup', 'bindMenu', 'bindContextMenu', 'bindContextMenuByResponseType', 'bindContextMenuByIsShow', 'bindContextMenuWithResponse', 'title',

  'menus', 'toolBar', 'tabBar', 'toolbar', 'onDragStart', 'onItemDragStart', 'swipeAction', 'bindContentCover', 'bindSheet',

  'navDestination', 'overlay', 'toolbarConfiguration', 'customKeyboard', 'bindSelectionMenu', 'description',

  'showUnit', 'customKeyboard', 'create', 'addBuilderSpan', 'dragPreview', 'accessibilityVirtualNode',

  'header', 'footer', 'subMenuBuilder']);

export const CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY: Set<string> = new Set(['showUnit', 'create', 'header', 'footer', 'subMenuBuilder']);

export const CUSTOM_BUILDER_CONSTRUCTORS: Set<string> = new Set(['MenuItem', 'MenuItemGroup', 'Refresh', 'WaterFlow', 'Radio', 'Checkbox']);



(function initComponent(): void {

  Object.keys(COMPONENT_MAP).forEach((componentName) => {

    INNER_COMPONENT_NAMES.add(componentName);

    JS_BIND_COMPONENTS.add(componentName);

    if (!COMPONENT_MAP[componentName].atomic) {

      BUILDIN_CONTAINER_COMPONENT.add(componentName);

    } else {

      AUTOMIC_COMPONENT.add(componentName);

    }

    if (COMPONENT_MAP[componentName].single) {

      SINGLE_CHILD_COMPONENT.add(componentName);

    }

    if (COMPONENT_MAP[componentName].children) {

      SPECIFIC_CHILD_COMPONENT.set(componentName,

        new Set([...COMPONENT_MAP[componentName].children]));

    }

    if (COMPONENT_MAP[componentName].attrs && COMPONENT_MAP[componentName].attrs.length) {

      COMPONENT_MAP[componentName].attrs.forEach((item: string) => {

        BUILDIN_STYLE_NAMES.add(item);

      });

      if (COMPONENT_MAP[componentName].systemApi) {

        COMPONENT_MAP[componentName].attrs.forEach((item: string) => {

          COMPONENT_SYSTEMAPI_NAMES.add(item);

        });

      }

    }

    if (COMPONENT_MAP[componentName].noDebugLine) {

      NO_DEBUG_LINE_COMPONENT.add(componentName);

    }

    if (COMPONENT_MAP[componentName].parents) {

      SPECIFIC_PARENT_COMPONENT.set(componentName,

        new Set([...COMPONENT_MAP[componentName].parents]));

    }

  });

})();



export function resetComponentMap(): void {

  ID_ATTRS.clear();

  EXTEND_ATTRIBUTE.clear();

  STYLES_ATTRIBUTE.clear();

}



export function resetExtContent(): void {

  EXT_WHITE_LIST = [];

}