text: import { ChildProcess } from 'child_process';
  import * as apid from '../../../../node_modules/mirakurun/api';
  import * as events from '../../IoEvents';
  import Model from '../Model';
  import { MirakurunManageModelInterface } from '../Operator/EPGUpdate/MirakurunManageModel';
  import { DeleteOption, ExternalFileInfo, NewRecorded, RecordedManageModelInterface } from '../Operator/Recorded/RecordedManageModel';
  import { RecordingManageModelInterface } from '../Operator/Recording/RecordingManageModel';
  import { ReservationManageModelInterface } from '../Operator/Reservation/ReservationManageModel';
  import { AddReserveInterface } from '../Operator/ReserveProgramInterface';
  import { RuleManageModelInterface } from '../Operator/Rule/RuleManageModel';
  import { RuleInterface } from '../Operator/RuleInterface';
  import { EncodeProgram } from '../Service/Encode/EncodeManageModel';
  import { IPCClientMessage, IPCMessageDefinition, IPCServerMessage } from './IPCMessageInterface';
  
  interface IPCServerInterface extends Model {
      setModels(
          mirakurunManage: MirakurunManageModelInterface,
          reservationManage: ReservationManageModelInterface,
          recordingManage: RecordingManageModelInterface,
          recordedManage: RecordedManageModelInterface,
          ruleManage: RuleManageModelInterface,
      ): void;
      register(child: ChildProcess): void;
      notifIo(): void;
      setEncode(program: EncodeProgram): void;
      updateEncodingProgramgStatus(recordedId: number): void;
  }
  
  /**
   * IPC 通信サーバ
   */
  class IPCServer extends Model implements IPCServerInterface {
      private mirakurunManage: MirakurunManageModelInterface;
      private reservationManage: ReservationManageModelInterface;
      private recordedManage: RecordedManageModelInterface;
      private recordingManage: RecordingManageModelInterface;
      private ruleManage: RuleManageModelInterface;
      private child: ChildProcess;
      private functions: {
          [key: string]: ((id: number, args: any) => void);
      } = {};
  
      constructor() {
          super();
          this.init();
      }
  
      /**
       * Model をセット
       */
      public setModels(
          mirakurunManage: MirakurunManageModelInterface,
          reservationManage: ReservationManageModelInterface,
          recordingManage: RecordingManageModelInterface,
          recordedManage: RecordedManageModelInterface,
          ruleManage: RuleManageModelInterface,
      ): void {
          this.mirakurunManage = mirakurunManage;
          this.reservationManage = reservationManage;
          this.recordingManage = recordingManage;
          this.recordedManage = recordedManage;
          this.ruleManage = ruleManage;
      }
  
      /**
       * メッセージ登録処理
       */
      public register(child: ChildProcess): void {
          this.child = child;
  
          this.child.on('message', async(msg: IPCClientMessage) => {
              if (typeof this.functions[msg.msg] !== 'undefined') {
                  this.functions[msg.msg](msg.id, msg.value);
              }
          });
      }
  
      /**
       * クライアントに socket.io message を依頼する
       */
      public notifIo(): void {
          this.child.send({ msg: events.updateStatus });
          this.log.access.debug('noifIo');
      }
  
      /**
       * クライアントへエンコードを依頼する
       */
      public setEncode(program: EncodeProgram): void {
          this.child.send({ msg: IPCMessageDefinition.setEncodeToClient, program: program });
      }
  
      /**
       * クライアントへ encoding 中の番組情報のサムネイル状態変更を通知する
       */
      public updateEncodingProgramgStatus(recordedId: number): void {
          this.child.send({
              msg: IPCMessageDefinition.updateEncodingProgramgStatusToClient,
              recordedId: recordedId,
          });
      }
  
  
      /**
       * クライアントにメッセージを送信
       */
      private send(msg: IPCServerMessage): void {
          this.child.send(msg);
      }
  
      /**
       * init
       */
      private init(): void {
          // MirakurunManager
          this.functions[IPCMessageDefinition.getTuners] = (id: number) => {
              const value = this.mirakurunManage.getTuners();
              this.send({ id: id, value: value });
          };
  
          // Reserves
          this.functions[IPCMessageDefinition.getReserveAllId] = (id: number) => {
              const value = this.reservationManage.getReservesAllId();
              this.send({ id: id, value: value });
          };
  
          this.functions[IPCMessageDefinition.getReserve] = (id: number, args: any) => {
              const programId: number = args.programId;
              const value = this.reservationManage.getReserve(programId);
              this.send({ id: id, value: value });
          };
  
          this.functions[IPCMessageDefinition.getReserves] = (id: number, args: any) => {
              const limit: number = args.limit;
              const offset: number = args.offset;
              const value = this.reservationManage.getReserves(limit, offset);
              this.send({ id: id, value: value });
          };
  
          this.functions[IPCMessageDefinition.getReserveConflicts] = (id: number, args: any) => {
              const limit: number = args.limit;
              const offset: number = args.offset;
              const value = this.reservationManage.getConflicts(limit, offset);
              this.send({ id: id, value: value });
          };
  
          this.functions[IPCMessageDefinition.getReserveSkips] = (id: number, args: any) => {
              const limit: number = args.limit;
              const offset: number = args.offset;
              const value = this.reservationManage.getSkips(limit, offset);
              this.send({ id: id, value: value });
          };
  
          this.functions[IPCMessageDefinition.getReserveOverlaps] = (id: number, args: any) => {
              const limit: number = args.limit;
              const offset: number = args.offset;
              const value = this.reservationManage.getOverlaps(limit, offset);
              this.send({ id: id, value: value });
          };
  
          this.functions[IPCMessageDefinition.getReservePosition] = (id: number, args: any) => {
              const programId: number = args.programId;
              const value = this.reservationManage.getPosition(programId);
              this.send({ id: id, value: value });
          };
  
          this.functions[IPCMessageDefinition.addReserve] = async(id: number, args: any) => {
              const option: AddReserveInterface = args.option;
  
              try {
                  const value = await this.reservationManage.addReserve(option);
                  this.send({ id: id, value: value });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.editReserve] = async(id: number, args: any) => {
              const option: AddReserveInterface = args.option;
  
              try {
                  await this.reservationManage.editReserve(option);
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.cancelReserve] = async(id: number, args: any) => {
              const programId: apid.ProgramId = args.programId;
  
              try {
                  await this.reservationManage.cancel(programId);
                  await this.recordingManage.stop(programId);
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.removeReserveSkip] = async(id: number, args: any) => {
              const programId: apid.ProgramId = args.programId;
  
              await this.reservationManage.removeSkip(programId);
              this.send({ id: id });
          };
  
          this.functions[IPCMessageDefinition.disableReserveOverlap] = async(id: number, args: any) => {
              const programId: apid.ProgramId = args.programId;
  
              await this.reservationManage.disableOverlap(programId);
              this.send({ id: id });
          };
  
          // Recorded
          this.functions[IPCMessageDefinition.recordedDelete] = async(id: number, args: any) => {
              const recordedId: number = args.recordedId;
  
              try {
                  await this.recordedManage.delete(recordedId);
                  this.send({ id: id });
              } catch (err) {
                   this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.recordedDeletes] = async(id: number, args: any) => {
              const recordedIds: number[] = args.recordedIds;
              const option: DeleteOption = args.option;
  
              try {
                  const value = await this.recordedManage.deletes(recordedIds, option);
                  this.send({ id: id,  value: value });
              } catch (err) {
                   this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.recordedFileDelete] = async(id: number, args: any) => {
              const recordedId: number = args.recordedId;
  
              try {
                  await this.recordedManage.deleteFile(recordedId);
                  this.send({ id: id });
              } catch (err) {
                   this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.recordedEncodeFileDelete] = async(id: number, args: any) => {
              const encodedId: number = args.encodedId;
  
              try {
                  await this.recordedManage.deleteEncodedFile(encodedId);
                  this.send({ id: id });
              } catch (err) {
                   this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.recordedClenaup] = async(id: number) => {
              try {
                  await this.recordedManage.cleanup();
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.recordedRegenerateThumbnail] = async(id: number) => {
              try {
                  await this.recordedManage.regenerateThumbnail();
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          // Rule
          this.functions[IPCMessageDefinition.ruleDisable] = async(id: number, args: any) => {
              const ruleId: number = args.ruleId;
  
              try {
                  await this.ruleManage.disable(ruleId);
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.ruleEnable] = async(id: number, args: any) => {
              const ruleId: number = args.ruleId;
  
              try {
                  await this.ruleManage.enable(ruleId);
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.ruleDelete] = async(id: number, args: any) => {
              const ruleId: number = args.ruleId;
  
              try {
                  await this.ruleManage.delete(ruleId);
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.ruleDeletes] = async(id: number, args: any) => {
              const ruleIds: number[] = args.ruleIds;
  
              try {
                  const value = await this.ruleManage.deletes(ruleIds);
                  this.send({ id: id,  value: value });
              } catch (err) {
                   this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.ruleAdd] = async(id: number, args: any) => {
              const rule: RuleInterface = args.rule;
  
              try {
                  const ruleId = await this.ruleManage.add(rule);
                  this.send({ id: id,  value: ruleId });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          this.functions[IPCMessageDefinition.ruleUpdate] = async(id: number, args: any) => {
              const ruleId: number = args.ruleId;
              const rule: RuleInterface = args.rule;
  
              try {
                  await this.ruleManage.update(ruleId, rule);
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          // add encoded file
          this.functions[IPCMessageDefinition.addEncodeFile] = async(id: number, args: any) => {
              const recordedId: number = args.recordedId;
              const name: string = args.name;
              const filePath: string = args.filePath;
  
              try {
                  const encodedId = await this.recordedManage.addEncodeFile(recordedId, name, filePath);
                  this.send({ id: id, value: encodedId });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          // add recorded externalFile
          this.functions[IPCMessageDefinition.addRecordedExternalFile] = async(id: number, args: any) => {
              const info: ExternalFileInfo = args.info;
  
              try {
                  await this.recordedManage.addRecordedExternalFile(info);
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          // create new recorded
          this.functions[IPCMessageDefinition.createNewRecorded] = async(id: number, args: any) => {
              const info: NewRecorded = args.info;
  
              try {
                  const recordedId = await this.recordedManage.createNewRecorded(info);
                  this.send({ id: id, value: recordedId });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          // update TS file size
          this.functions[IPCMessageDefinition.updateTsFileSize] = async(id: number, args: any) => {
              const recordedId: number = args.recordedId;
  
              try {
                  await this.recordedManage.updateTsFileSize(recordedId);
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          // update encoded file size
          this.functions[IPCMessageDefinition.updateEncodedFileSize] = async(id: number, args: any) => {
              const encodedId: number = args.encodedId;
  
              try {
                  await this.recordedManage.updateEncodedFileSize(encodedId);
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
  
          // update Reserves
          this.functions[IPCMessageDefinition.updateReserves] = async(id: number) => {
              try {
                  this.mirakurunManage.update();
                  this.send({ id: id });
              } catch (err) {
                  this.send({ id: id, error: err.message });
              }
          };
      }
  }
  
  export { IPCServerInterface, IPCServer };
  
  