/*
 * Copyright (C) 2024 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.
 */
import { ImageKnifeRequest, ImageKnifeRequestState } from './model/ImageKnifeRequest'
import { DefaultJobQueue } from './queue/DefaultJobQueue'
import { IJobQueue } from './queue/IJobQueue'
import List from '@ohos.util.List';
import LightWeightMap from '@ohos.util.LightWeightMap';
import { LogUtil } from './utils/LogUtil';
import { ImageKnife } from './ImageKnife';
import { ImageKnifeData, CacheStrategy, TimeInfo, ErrorInfo, ImageKnifeCheckRequest } from './model/ImageKnifeData';
import image from '@ohos.multimedia.image';
import emitter from '@ohos.events.emitter';
import { Constants, LoadPhase, LoadPixelMapCode } from './utils/Constants';
import taskpool from '@ohos.taskpool';
import { IEngineKey } from './key/IEngineKey';
import { DefaultEngineKey } from './key/DefaultEngineKey';
import {
  ImageKnifeRequestWithSource,
  ImageKnifeRequestSource,
  RequestJobResult,
  RequestJobRequest
} from './model/ImageKnifeData'
import { BusinessError } from '@kit.BasicServicesKit';
import { ImageKnifeLoader } from './ImageKnifeLoader'
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
import { hiTraceMeter } from '@kit.PerformanceAnalysisKit';
import { sendableImage } from '@kit.ImageKit';


export class ImageKnifeDispatcher {
  // 最大并发
  private maxRequests: number = 8
  // 排队队列
  private jobQueue: IJobQueue = new DefaultJobQueue()
  // 执行中的请求
  executingJobMap: LightWeightMap<string, List<ImageKnifeRequestWithSource>> = new LightWeightMap();
  // 开发者可配置全局缓存
  private engineKey: IEngineKey = new DefaultEngineKey();

  showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): boolean {
    LogUtil.log('showFromMemomry.start:' + request.componentId  + ',srcType:' + requestSource + ',version:' + request.componentVersion + ' isAnimator=' + isAnimator)
    let memoryCache: ImageKnifeData | undefined;
    let memoryCheckStartTime = Date.now();
    if (requestSource === ImageKnifeRequestSource.SRC) {
      if ((typeof (request.imageKnifeOption.loadSrc as image.PixelMap)?.isEditable) == 'boolean') {
        memoryCache = {
          source: request.imageKnifeOption.loadSrc as image.PixelMap,
          imageWidth: 0,
          imageHeight: 0,
        }
      } else {
        hiTraceMeter.startTrace('getMemoryCache',request.componentId)
        memoryCache = ImageKnife.getInstance()
          .loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,isAnimator, request.componentWidth, request.componentHeight));
        hiTraceMeter.finishTrace('getMemoryCache',request.componentId)
      }
    } else {
      if (typeof imageSrc !== 'string') {
        request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, imageSrc, requestSource)
        return true
      } else {
        memoryCache = ImageKnife.getInstance()
          .loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,isAnimator, request.componentWidth, request.componentHeight));
      }
    }


    //记录ImageKnifeRequestSource.SRC 开始内存检查的时间点
    if (requestSource == ImageKnifeRequestSource.SRC && request.imageKnifeData) {
      let timeInfo = request.imageKnifeData?.timeInfo
      if (timeInfo) {
        timeInfo.memoryCheckStartTime = memoryCheckStartTime;
        timeInfo.memoryCheckEndTime = Date.now();
        //设置请求结束的时间点
        if (memoryCache !== undefined) {
          timeInfo.requestEndTime = Date.now();
        }
      }
    }

    if (memoryCache !== undefined) {
      // 画主图
      if (request.requestState === ImageKnifeRequestState.PROGRESS) {
        // 回调请求开始
        if (requestSource === ImageKnifeRequestSource.SRC && request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) {
          request.imageKnifeOption.onLoadListener.onLoadStart(request)
        }
        request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source, requestSource,
          { width: memoryCache.imageWidth, height: memoryCache.imageHeight }, memoryCache.imageAnimator)

        if (requestSource == ImageKnifeRequestSource.SRC) {
          request.requestState = ImageKnifeRequestState.COMPLETE
          request.drawMainSuccess = true
          // 回调请求开结束
          if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) {
            this.copyMemoryCacheInfo(memoryCache, request.imageKnifeData);
            request.imageKnifeOption.onLoadListener.onLoadSuccess(memoryCache.source, memoryCache, request)
          }
        } else if (requestSource == ImageKnifeRequestSource.ERROR_HOLDER) {
          request.requestState = ImageKnifeRequestState.ERROR
        }
      }
      LogUtil.log('showFromMemomry.end_hasmemory:' + request.componentId  + ',srcType:' + requestSource + ',version:' + request.componentVersion)
      return true
    }
    LogUtil.log('showFromMemomry.end_nomemory:' + request.componentId  + ',srcType:' + requestSource + ',version:' + request.componentVersion)
    return false
  }

  private copyMemoryCacheInfo(memoryCache: ImageKnifeData | undefined, target: ImageKnifeData | undefined) {
    if (!memoryCache || !target) {
      return;
    }
    target.source = memoryCache.source;
    target.imageWidth = memoryCache.imageWidth;
    target.imageHeight = memoryCache.imageHeight;
    target.type = memoryCache.type;
    target.bufSize = memoryCache.bufSize
    target.imageAnimator = memoryCache.imageAnimator;
  }

  private assembleImageKnifeData(beforeCallData: ImageKnifeData | undefined, afterCallData: ImageKnifeData | undefined, req: ImageKnifeRequest) {
    if (!beforeCallData || !afterCallData || !req) {
      return;
    }
    //设置图片开始加载时间及其缓存检查时间点
    if (beforeCallData.timeInfo) {
      if (afterCallData.timeInfo) {
        afterCallData.timeInfo.requestStartTime = beforeCallData.timeInfo.requestStartTime;
        afterCallData.timeInfo.memoryCheckStartTime = beforeCallData.timeInfo.memoryCheckStartTime;
        afterCallData.timeInfo.memoryCheckEndTime = beforeCallData.timeInfo.memoryCheckEndTime;
      }
    }
    req.imageKnifeData = afterCallData;
  }

  private initCallData(request: ImageKnifeRequest) {
    if (!request) {
      return
    }
    //图片加载信息回调数据
    let callBackData: ImageKnifeData = {
      source: '',
      imageWidth: 0,
      imageHeight: 0,
    };

    //图片加载信息回调数据时间点
    let callBackTimeInfo: TimeInfo = {};
    callBackTimeInfo.requestStartTime = Date.now();
    callBackData.timeInfo = callBackTimeInfo;

    //跟隨請求保存回調信息點
    request.imageKnifeData = callBackData;
  }

  enqueue(request: ImageKnifeRequest,): void {
    //初始化加载回调信息
    this.initCallData(request);
    //1.内存有的话直接渲染
    if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,request.animator)) {
      return
    }
    // 2.内存获取占位图
    if (request.imageKnifeOption.placeholderSrc !== undefined) {
      if (this.showFromMemomry(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)) {
        request.drawPlayHolderSuccess = true
      }
    }
    this.executeJob(request)
  }

  checkRepeatRequests(request: ImageKnifeRequest,imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): ImageKnifeCheckRequest | undefined {
    let memoryKey: string = this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,
      requestSource === ImageKnifeRequestSource.SRC ? request.animator : undefined, request.componentWidth,
      request.componentHeight)
    //3.判断是否要排队
    if (this.executingJobMap.length >= this.maxRequests && !this.executingJobMap.get(memoryKey) && requestSource === ImageKnifeRequestSource.SRC) {
      this.jobQueue.add(request)
      return
    }
    if (request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined && requestSource === ImageKnifeRequestSource.SRC) {
      request.imageKnifeOption.onLoadListener?.onLoadStart(request)
    }
    let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(memoryKey)
    if (requestList === undefined) {
      requestList = new List()
      requestList.add({ request: request, source: requestSource })
      this.executingJobMap.set(memoryKey, requestList)
      return {
        memoryKey,
        requestList
      }
    } else {
      requestList.add({ request: request, source: requestSource })
      return
    }
  }

  executeJob(request: ImageKnifeRequest): void {
    LogUtil.log('executeJob.start:' + request.componentId  + ',version:' + request.componentVersion)
    // 加载占位符
    if (request.imageKnifeOption.placeholderSrc !== undefined && request.drawPlayHolderSuccess == false) {
      request.drawPlayHolderSuccess = true
      let checkRequests =
        this.checkRepeatRequests(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)
      if (checkRequests) {
        this.getAndShowImage(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER,
          checkRequests.memoryKey, checkRequests.requestList)
      }
    }
    let checkRequests =
      this.checkRepeatRequests(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC)
    if (checkRequests) {
      // 加载主图
      this.getAndShowImage(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,
        checkRequests.memoryKey, checkRequests.requestList, request.animator)
    }
    LogUtil.log('executeJob.end:' + request.componentId  + ',version:' + request.componentVersion)
  }

  /**
   * 获取和显示图片
   */
  getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource,
    requestSource: ImageKnifeRequestSource, memoryKey: string, requestList: List<ImageKnifeRequestWithSource>,
    isAnimator?: boolean): void {
    LogUtil.log('getAndShowImage.start:'  + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
    if (requestSource === ImageKnifeRequestSource.SRC && imageSrc === 'ImageKnife') {
      this.executingJobMap.remove(memoryKey)
      this.dispatchNextJob()
      LogUtil.error('loadSrc parameter is not passed:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
      return
    }
    LogUtil.info('image load getAndShowImage start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
    let isWatchProgress : boolean = false
    if (currentRequest.imageKnifeOption.progressListener !== undefined && requestSource === ImageKnifeRequestSource.SRC) {
      isWatchProgress = true
    }

    let src: string | number = ''
    let moduleName: string = ''
    let resName: string = ''
    if((imageSrc as Resource)?.id != undefined) {
      moduleName = (imageSrc as Resource).moduleName
      src = (imageSrc as Resource).id
      resName = (imageSrc as Resource).params![0]
    } else if(typeof imageSrc == 'string') {
      src = imageSrc
    }
    let request: RequestJobRequest = {
      context: currentRequest.context,
      src: src,
      headers: currentRequest.imageKnifeOption.headerOption,
      allHeaders: currentRequest.headers,
      componentWidth:currentRequest.componentWidth,
      componentHeight:currentRequest.componentHeight,
      customGetImage: currentRequest.imageKnifeOption.customGetImage,
      onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache,
      transformation: currentRequest.imageKnifeOption.transformation,
      writeCacheStrategy: ImageKnife.getInstance()
        .isFileCacheInit() ? currentRequest.imageKnifeOption.writeCacheStrategy : CacheStrategy.Memory, // 未初始化文件缓存时,不写文件缓存
      engineKey: this.engineKey,
      signature: currentRequest.imageKnifeOption.signature,
      requestSource: requestSource,
      isWatchProgress: isWatchProgress,
      memoryKey: memoryKey,
      fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(),
      isAnimator:isAnimator,
      moduleName: moduleName == '' ? undefined : moduleName,
      resName: resName == '' ? undefined : resName,
      targetWidth: currentRequest.componentWidth,
      targetHeight: currentRequest.componentHeight,
      downsampType: currentRequest.imageKnifeOption.downsampleOf == undefined ? DownsampleStrategy.DEFAULT : currentRequest.imageKnifeOption.downsampleOf,
      isAutoImageFit: currentRequest.imageKnifeOption.objectFit == ImageFit.Auto,
      componentId: currentRequest.componentId,
      componentVersion: currentRequest.componentVersion,
      caPath: currentRequest.imageKnifeOption.httpOption?.caPath,
      connectTimeout: currentRequest.imageKnifeOption.httpOption?.connectTimeout ?? ImageKnife.getInstance().getConnectTimeout(),
      readTimeout: currentRequest.imageKnifeOption.httpOption?.readTimeout ?? ImageKnife.getInstance().getReadTimeout(),
      dnsOverHttps: currentRequest.imageKnifeOption.httpOption?.dnsOverHttps,
      dnsServers: currentRequest.imageKnifeOption.httpOption?.dnsServers,
      remoteValidation: currentRequest.imageKnifeOption.httpOption?.remoteValidation,
      pixelName: currentRequest.imageKnifeOption.pixelName,
      dynamicRangeMode: currentRequest.imageKnifeOption.dynamicRangeMode,
      jpegOptimizeDecoding: ImageKnife.getInstance().getJpegOptimizeDecoding()
    }

    if(request.customGetImage == undefined) {
      request.customGetImage = ImageKnife.getInstance().getCustomGetImage()
    }
    emitter.on(Constants.CALLBACK_EMITTER + memoryKey,(data)=>{
      emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
      let res = data?.data?.value as RequestJobResult | undefined
      this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
      if (isWatchProgress){
        emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
      }
      LogUtil.log('getAndShowImage.end:'+ currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
    })
    if (ImageKnife.getInstance().isRequestInSubThread){
      // 启动线程下载和解码主图
      LogUtil.log('etAndShowImage_Task.start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
      let task = new taskpool.Task(requestJob, request)
      LogUtil.log('getAndShowImage_Task.end:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
      if (isWatchProgress){
        emitter.on(Constants.PROGRESS_EMITTER + memoryKey, (data) => {
          this.progressCallBack(requestList! , data?.data?.value as number)
        });
      }

      LogUtil.log('getAndShowImage_execute.start(subthread):' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
      taskpool.execute(task).then((res: Object) => {
      }).catch((err: BusinessError) => {
        emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
        LogUtil.error('Fail to requestJob in sub thread err=' + err + ',id:' + currentRequest.componentId +
          ',version:' + currentRequest.componentVersion + ',url:' + imageSrc)
        if (isWatchProgress){
          emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
        }

        this.doTaskCallback({
          pixelMap: undefined,
          bufferSize: 0,
          fileKey: '',
          loadFail: 'Fail to requestJob in sub thread err=' + err,
          imageKnifeData: {
            source: '',
            imageWidth: 0,
            imageHeight: 0,
            timeInfo: { requestEndTime: Date.now() },
            errorInfo: {
              phase: LoadPhase.PHASE_LOAD,
              code: LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE,
            }
          }
        }, requestList!, currentRequest, memoryKey, imageSrc, requestSource, isAnimator)
      })
      currentRequest.taskRequest = task
    } else { //主线程请求
      LogUtil.log('getAndShowImage_execute.start(mainthread):' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
      requestJob(request, requestList).then(() => {
      }).catch((err: BusinessError) => {
        emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
        LogUtil.error('Fail to requestJob in sub thread err=' + err + ',id:' + currentRequest.componentId +
          ',version:' + currentRequest.componentVersion + ',url:' + imageSrc)

        this.doTaskCallback({
          pixelMap: undefined,
          bufferSize: 0,
          fileKey: '',
          loadFail: 'Fail to requestJob in main thread err=' + err,
          imageKnifeData: {
            source: '',
            imageWidth: 0,
            imageHeight: 0,
            timeInfo: { requestEndTime: Date.now() },
            errorInfo: {
              phase: LoadPhase.PHASE_LOAD,
              code: LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE,
            }
          }
        }, requestList!, currentRequest, memoryKey, imageSrc, requestSource, isAnimator)
      })
    }
  }

  /**
   * 回调下载进度
   * @param requestList 请求列表
   * @param data 进度
   */
  private progressCallBack(requestList:List<ImageKnifeRequestWithSource>, data: number) {
    for (let i = 0; i < requestList.length; i++) {
      let requestWithSource:ImageKnifeRequestWithSource = requestList[i]
      if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) {
        requestWithSource.request.imageKnifeOption.progressListener(data)
      }
    }
  }

  private doTaskCallback(requestJobResult: RequestJobResult | undefined, requestList: List<ImageKnifeRequestWithSource> ,
    currentRequest: ImageKnifeRequest, memoryKey: string, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean):void {
    LogUtil.log('getAndShowImage_CallBack.start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
    if (requestJobResult === undefined){
      return
    }

    //设置请求结束的时间
    if (requestJobResult.imageKnifeData && requestJobResult.imageKnifeData.timeInfo) {
      requestJobResult.imageKnifeData.timeInfo.requestEndTime = Date.now();
    }


    // 保存文件缓存
    if (requestJobResult.bufferSize > 0 && currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.Memory) {
      LogUtil.log('getAndShowImage_saveWithoutWriteFile.start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
      ImageKnife.getInstance().saveWithoutWriteFile(requestJobResult.fileKey, requestJobResult.bufferSize);
      LogUtil.log('getAndShowImage_saveWithoutWriteFile.end:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
    }

    let pixelmap = requestJobResult.pixelMap;
    // 请求取消
    if (currentRequest.requestState === ImageKnifeRequestState.DESTROY) {
      this.executingJobMap.remove(memoryKey);
      requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
        if ((currentRequest.componentId !== requestWithSource.request.componentId ||
          currentRequest.componentVersion !== requestWithSource.request.componentVersion) &&
          requestWithSource.request.requestState !== ImageKnifeRequestState.DESTROY) {
          // 加载占位符
          if (requestWithSource.source === ImageKnifeRequestSource.PLACE_HOLDER &&
            requestWithSource.request.imageKnifeOption.placeholderSrc !== undefined &&
            requestWithSource.request.drawPlayHolderSuccess == false) {
            let checkRequests =
              this.checkRepeatRequests(requestWithSource.request,
                requestWithSource.request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)
            if (checkRequests) {
              this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.placeholderSrc,
                ImageKnifeRequestSource.PLACE_HOLDER,
                checkRequests.memoryKey, checkRequests.requestList)
            }
          } else if (requestWithSource.source === ImageKnifeRequestSource.ERROR_HOLDER &&
            requestWithSource.request.imageKnifeOption.errorholderSrc !== undefined) {
            let checkRequests =
              this.checkRepeatRequests(requestWithSource.request,
                requestWithSource.request.imageKnifeOption.errorholderSrc, ImageKnifeRequestSource.ERROR_HOLDER)
            if (checkRequests) {
              this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc,
                ImageKnifeRequestSource.ERROR_HOLDER,
                checkRequests.memoryKey, checkRequests.requestList)
            }
          } else if (requestWithSource.source === ImageKnifeRequestSource.SRC) {
            let checkRequests =
              this.checkRepeatRequests(requestWithSource.request, requestWithSource.request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC)
            if (checkRequests) {
              // 加载主图
              this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,
                checkRequests.memoryKey, checkRequests.requestList, requestWithSource.request.animator)
            }
          }
        } else {
          if (pixelmap !== undefined && typeof pixelmap !== 'string') {
            (pixelmap as PixelMap).release()
          }
          if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) {
            // 回调请求成功
            // 回调请求成功
            //设置失败回调的时间点
            let callBackData = requestWithSource.request.imageKnifeData;

            if (requestJobResult.imageKnifeData && requestJobResult.imageKnifeData.timeInfo) {
              requestJobResult.imageKnifeData.timeInfo.requestCancelTime = Date.now();
              if (requestJobResult.imageKnifeData.errorInfo) {
                requestJobResult.imageKnifeData.errorInfo.phase = LoadPhase.PHASE_WILL_SHOW;
                requestJobResult.imageKnifeData.errorInfo.code = LoadPixelMapCode.IMAGE_LOAD_CANCEL_FAILED_CODE;
              }
            }
            this.assembleImageKnifeData(callBackData,requestJobResult.imageKnifeData,requestWithSource.request)
            LogUtil.log('getAndShowImage cancel:' + requestWithSource.request.componentId  + ',srcType:' + requestSource + ',version:' + requestWithSource.request.componentVersion)
            requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel(requestJobResult.loadFail ?? 'component has destroyed from load', requestWithSource.request)
          }
        }
      })
      this.dispatchNextJob()
      return
    }
    // 请求失败
    if (pixelmap === undefined) {
      this.executingJobMap.remove(memoryKey);
      requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
        if (requestWithSource.source === ImageKnifeRequestSource.SRC) {
          requestWithSource.request.requestState = ImageKnifeRequestState.ERROR
        }
        LogUtil.error('getAndShowImage_CallBack.pixelmap failed:' + requestWithSource.request.componentId + ',srcType:' +
          requestSource + ',version:' + requestWithSource.request.componentVersion + " error: " + requestJobResult.loadFail)
        // 主图回调请求失败
        if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
          requestWithSource.request.ImageKnifeRequestCallback?.mainLoadError && requestJobResult.loadFail) {
          requestWithSource.request.ImageKnifeRequestCallback?.mainLoadError(requestJobResult.loadFail)
        }
        // 主图请求失败回调
        if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
          requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadFailed !== undefined &&
        requestJobResult.loadFail) {
          this.assembleImageKnifeData(requestWithSource.request.imageKnifeData, requestJobResult.imageKnifeData,
            requestWithSource.request)
          requestWithSource.request.imageKnifeOption.onLoadListener.onLoadFailed(requestJobResult.loadFail,
            requestWithSource.request);
        }
        // 主图请求失败,加载错误图
        if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
          requestWithSource.request.imageKnifeOption.errorholderSrc !== undefined) {
          requestWithSource.request.requestState = ImageKnifeRequestState.PROGRESS
          if (this.showFromMemomry(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc,
            ImageKnifeRequestSource.ERROR_HOLDER) === false) {
            let checkRequests =
              this.checkRepeatRequests(requestWithSource.request,
                requestWithSource.request.imageKnifeOption.errorholderSrc, ImageKnifeRequestSource.ERROR_HOLDER)
            if (checkRequests) {
              this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc,
                ImageKnifeRequestSource.ERROR_HOLDER,
                checkRequests.memoryKey, checkRequests.requestList)
            }
          }
        }
      });
      this.dispatchNextJob();
      return;
    }
    let pixel = typeof pixelmap === 'string' ? pixelmap : sendableImage.convertToPixelMap(pixelmap)
    let imageKnifeData: ImageKnifeData;
    if (!requestJobResult.imageKnifeData) {
      imageKnifeData = {
        source: pixel,
        imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width,
        imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height,
        type: requestJobResult.type,
      };
    } else {
      imageKnifeData = requestJobResult.imageKnifeData;
      imageKnifeData.source = pixel;
    }

    if(requestJobResult.pixelMapList != undefined) {
      let imageAnimator: Array<ImageFrameInfo> = []
      requestJobResult.pixelMapList.forEach((item,index)=>{
        imageAnimator.push({
          src: sendableImage.convertToPixelMap(requestJobResult.pixelMapList![index]),
          duration:requestJobResult.delayList![index]
        })
      })
      imageKnifeData.imageAnimator = imageAnimator
    }

    //构建缓存保存的ImageKnifeData
    let saveCacheImageData: ImageKnifeData = {
      source: pixel,
      imageWidth: requestJobResult.size?.width ?? 0,
      imageHeight: requestJobResult.size?.height ?? 0,
      type: requestJobResult.type,
      bufSize: requestJobResult.bufferSize,
      imageAnimator: imageKnifeData.imageAnimator
    }

    // 保存内存缓存
    if (currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.File) {
      LogUtil.log('getAndShowImage_saveMemoryCache.start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
      hiTraceMeter.startTrace('saveMemoryCache',currentRequest.componentId)
      ImageKnife.getInstance()
        .saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator, currentRequest.componentWidth, currentRequest.componentHeight),
          saveCacheImageData);
      hiTraceMeter.finishTrace('saveMemoryCache',currentRequest.componentId)
      LogUtil.log('getAndShowImage_saveMemoryCache.end:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
    }
    if (requestList !== undefined) {
      // key相同的request,一起绘制
      requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
        // 画主图
        if (requestWithSource.source === ImageKnifeRequestSource.SRC ||
          requestWithSource.source === ImageKnifeRequestSource.ERROR_HOLDER
          || (requestWithSource.source === ImageKnifeRequestSource.PLACE_HOLDER &&
            requestWithSource.request.requestState === ImageKnifeRequestState.PROGRESS)) {
          requestWithSource.request.ImageKnifeRequestCallback?.showPixelMap(requestWithSource.request.componentVersion,
            imageKnifeData.source, requestWithSource.source,
            { width: imageKnifeData.imageWidth, height: imageKnifeData.imageHeight },
            imageKnifeData.imageAnimator);
        }

        if (requestWithSource.source == ImageKnifeRequestSource.SRC) {
          requestWithSource.request.requestState = ImageKnifeRequestState.COMPLETE;
          requestWithSource.request.drawMainSuccess = true
          if (requestWithSource.request.imageKnifeOption.onLoadListener &&
          requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess) {
            // 回调请求成功
            this.assembleImageKnifeData(requestWithSource.request.imageKnifeData, imageKnifeData,
              requestWithSource.request);
            requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(imageKnifeData.source,
              saveCacheImageData, requestWithSource.request);
          }
        } else if (requestWithSource.source == ImageKnifeRequestSource.ERROR_HOLDER) {
          requestWithSource.request.requestState = ImageKnifeRequestState.ERROR;
        } else {
          requestWithSource.request.drawPlayHolderSuccess = true
        }
      });
      this.executingJobMap.remove(memoryKey);
      this.dispatchNextJob();
    } else {
      LogUtil.log('error: no requestlist need to draw for key = ' + memoryKey);
    }
    LogUtil.log('getAndShowImage_CallBack.end:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
  }


  dispatchNextJob() {
    LogUtil.log('dispatchNextJob.start')

    // 主图和错误图并发加载时,以及主图加载失败后立即加载错误图,可能会导致短时间内并发数超过maxRequests,故此处减少响应的并发
    if (this.executingJobMap.length >= this.maxRequests) {
      return
    }

    while (true) {
      let request = this.jobQueue.pop()
      if (request === undefined) {
        LogUtil.log('dispatchNextJob.end:no any job')
        break // 队列已无任务
      }
      else if (request.requestState === ImageKnifeRequestState.PROGRESS) {
        LogUtil.log('dispatchNextJob.start executeJob:' + request.componentId  + ',version:' + request.componentVersion)
        this.executeJob(request)
        LogUtil.log('dispatchNextJob.end executeJob:' + request.componentId  + ',version:' + request.componentVersion)
        break
      }else if (request.requestState == ImageKnifeRequestState.DESTROY && request.imageKnifeOption.onLoadListener?.onLoadCancel) {
        //构建回调错误信息
        let callBackData = request.imageKnifeData;
        if (callBackData) {
          let timeInfo: TimeInfo =  ImageKnifeLoader.getTimeInfo(callBackData)
          timeInfo.requestCancelTime = Date.now();
          timeInfo.requestEndTime = Date.now()
          let errorInfo: ErrorInfo = {
            phase: LoadPhase.PHASE_THREAD_QUEUE,
            code: LoadPixelMapCode.IMAGE_LOAD_CANCEL_FAILED_CODE,
          };
          callBackData.errorInfo = errorInfo;
        }
        LogUtil.log('dispatchNextJob cancel:' + request.componentId  + ',version:' + request.componentVersion)
        request.imageKnifeOption.onLoadListener.onLoadCancel('component has destroyed from queue', request)
      }
    }
  }

  setMaxRequests(concurrency: number): void {
    if (concurrency > 0) {
      this.maxRequests = concurrency
    }
  }

  setEngineKeyImpl(impl: IEngineKey): void {
    this.engineKey = impl;
  }

  getEngineKeyImpl(): IEngineKey {
    return this.engineKey;
  }
}

/**
 * 通过taskpool 二级缓存,下载/读取本地文件,编解码
 * @param context
 * @param src
 * @returns
 */
@Concurrent
async function requestJob(request: RequestJobRequest, requestList?: List<ImageKnifeRequestWithSource>) {
  LogUtil.log('requestJob.start:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
  let src = typeof request.src == 'number' ? request.resName != undefined ? request.resName : request.src + '' : request.src
  // 生成文件缓存key
  let fileKey = request.engineKey.generateFileKey(src, request.signature, request.isAnimator)

  //获取图片资源
  ImageKnifeLoader.execute(request,requestList,fileKey)

}