import { AMCPUtil as AMCPUtilNS } from './AMCP' ; import CasparCGSocketResponse = AMCPUtilNS . CasparCGSocketResponse ; import { Response as ResponseNS } from './ResponseSignature' ; import ResponseSignature = ResponseNS . ResponseSignature ; import { Response as ResponseValidatorNS } from './ResponseValidators' ; import IResponseValidator = ResponseValidatorNS . IResponseValidator ; import { Response as ResponseParserNS } from './ResponseParsers' ; import IResponseParser = ResponseParserNS . IResponseParser ; import { Param as ParamNS } from './ParamSignature' ; import Payload = ParamNS . Payload ; import PayloadVO = ParamNS . PayloadVO ; import Param = ParamNS . Param ; import ParamData = ParamNS . ParamData ; import IParamSignature = ParamNS . IParamSignature ; import { Validation as ValidationNS } from './ParamValidators' ; import PositiveNumberValidatorBetween = ValidationNS . PositiveNumberRoundValidatorBetween ; import { Protocol as ProtocolNS } from './ProtocolLogic' ; import IProtocolLogic = ProtocolNS . IProtocolLogic ; import { Callback as CallbackNS } from './global/Callback' ; import ICommandStatusCallback = CallbackNS . ICommandStatusCallback ; /**
 *
 */ export namespace Command { /**
     *
     */ export interface IAMCPResponse { code : number ; raw : string ; data : any ; toString ( ) : string ; } /**
     *
     */ export class AMCPResponse implements IAMCPResponse { public code : number ; public raw : string ; public data : any ; public toString ( ) { return this . raw . replace ( /\r?\n|\r/gi , '' ) ; } } /**
     *
     */ export enum IAMCPStatus { Invalid = - 1 , New = 0 , Initialized = 1 , Queued = 2 , Sent = 3 , Suceeded = 4 , Failed = 5 , Timeout = 6 } /**
     *
     */ export interface IAMCPCommandData { address : string ; channel : number ; layer : number ; payload : PayloadVO ; response : IAMCPResponse ; status : IAMCPStatus ; id : string ; readonly name : string ; } /**
     *
     */ export interface IAMCPCommandVO extends IAMCPCommandData { _commandName : string ; _objectParams : Param ; _stringParamsArray : Array < string > ; } /**
     *
     */ export interface IAMCPCommand extends IAMCPCommandData { paramProtocol : Array < IParamSignature > ; protocolLogic : Array < IProtocolLogic > ; responseProtocol : ResponseSignature ; onStatusChanged : ICommandStatusCallback ; token : string ; resolve : ( command : IAMCPCommand ) => void ; reject : ( command : IAMCPCommand ) => void ; getParam : ( name : string ) => string | number | boolean | Object | undefined ; validateParams ( ) : boolean ; validateResponse ( response ) : boolean ; serialize ( ) : IAMCPCommandVO ; populate ( cmdVO , id ) : void ; } /**
     *
     */ export abstract class AbstractCommand implements IAMCPCommand { response : IAMCPResponse = new AMCPResponse ( ) ; paramProtocol : Array < IParamSignature > ; responseProtocol : ResponseSignature = new ResponseSignature ( ) ; onStatusChanged : ICommandStatusCallback ; resolve : ( command : IAMCPCommand ) => void ; reject : ( command : IAMCPCommand ) => void ; protected _channel : number ; protected _layer : number ; protected _id : string ; protected _payload : PayloadVO = { } ; protected _stringParamsArray : Array < string > ; protected _objectParams : Param ; protected _token : string ; private _status : IAMCPStatus = IAMCPStatus . New ; /**
         *
         */ constructor ( params ? , public context ? ) { let paramsArray = [ ] ; if ( Array . isArray ( params ) ) { paramsArray = params ; } else { paramsArray = [ params as string | Param ] ; } this . _stringParamsArray = [ ] ; this . _objectParams = { } ; this . _token = Math . random ( ) . toString ( 35 ) . substr ( 2 , 7 ) ; for ( let element of paramsArray ) { if ( typeof element === 'string' ) { element = element . toString ( ) . trim ( ) ; this . _stringParamsArray = this . _stringParamsArray . concat ( [ ... element . toString ( ) . split ( /\s+/ ) ] ) ; } else { for ( let prop in element ) { this . _objectParams [ prop ] = element [ prop ] ; } } } } /**
         *
         */ public validateParams ( ) { let required = this . paramProtocol ? this . paramProtocol . filter ( signature => signature . required . valueOf ( ) === true ) : [ ] ; let optional = this . paramProtocol ? this . paramProtocol . filter ( signature => signature . required . valueOf ( ) === false ) : [ ] ; for ( let signature of required ) { if ( ! this . validateParam ( signature ) ) { return false ; } } optional . forEach ( ( signature ) => { this . validateParam ( signature ) ; } ) ; if ( ! this . validateProtocolLogic ( ) ) { return false ; } let validParams = this . paramProtocol ? this . paramProtocol . filter ( ( param ) => param . resolved && param . payload !== null ) : [ ] ; let invalidParams = this . paramProtocol ? this . paramProtocol . filter ( ( param ) => param . resolved && param . payload === null && param . required . valueOf ( ) === true ) : [ ] ; if ( invalidParams . length > 0 ) { return false ; } validParams . forEach ( ( param ) => { let payload = { key : '' , value : { } , raw : null } ; payload . key = param . key || '' ; payload . value = param . payload !== null ? param . payload : { } ; payload . raw = param . raw ; this . payload [ param . name ] = payload ; } ) ; return true ; } public getParam ( name ) { if ( this . _objectParams [ name ] ) { return this . _objectParams [ name ] ; } return undefined ; } /**
         *
         */ public validateResponse ( response ) { this . response . raw = response . responseString ; this . response . code = response . statusCode ; if ( response . statusCode !== this . responseProtocol . code ) { return false ; } let validData = { } ; if ( this . responseProtocol . validator ) { const validator = new this . responseProtocol . validator ( ) ; validData = validator . resolve ( response ) ; if ( validData === false ) { return false ; } } if ( this . responseProtocol . parser && validData ) { const parser = new this . responseProtocol . parser ( ) ; parser . context = this . context ; validData = parser . parse ( validData ) ; if ( validData === false ) { return false ; } } this . response . data = validData ; return true ; } /**
         *
         */ get payload ( ) : PayloadVO { return this . _payload ; } /**
         *
         */ get id ( ) : string { return this . _id || ( new Date ( ) . getTime ( ) + Math . random ( ) * 100 ) . toString ( ) ; } /**
         *
         */ get name ( ) : string { return this . constructor . name ; } /**
         *
         */ get protocolLogic ( ) : Array < IProtocolLogic > { return ( this . constructor as any ) . protocolLogic || [ ] ; } /**
         *
         */ get channel ( ) : number { return - 1 ; } /**
         *
         */ get layer ( ) : number { return - 1 ; } /**
         *
         */ get address ( ) : string { return '' ; } get token ( ) : string { return this . _token ; } /**
         *
         */ get status ( ) : IAMCPStatus { return this . _status ; } /**
         *
         */ set status ( code ) { if ( code !== this . _status ) { this . _status = code ; if ( this . onStatusChanged ) { this . onStatusChanged ( this . _status ) ; } } } /**
         *
         */ public serialize ( ) { return { channel : this . channel , layer : this . layer , payload : this . payload , response : this . response , status : this . status , _commandName : this . constructor [ 'name' ] , _objectParams : this . _objectParams , _stringParamsArray : this . _stringParamsArray } as IAMCPCommandVO ; } /**
         *
         */ populate ( cmdVO , id ) { this . _stringParamsArray = cmdVO . _stringParamsArray ; this . _objectParams = cmdVO . _objectParams ; this . response = cmdVO . response ; this . _id = id ; } /**
         *
         */ public toString ( ) { let message = '' ; switch ( this . status ) { case IAMCPStatus . Invalid : message = 'Invalid command' ; break ; case IAMCPStatus . New : message = 'New command' ; break ; case IAMCPStatus . Queued : message = 'Queued command' ; break ; case IAMCPStatus . Sent : message = 'Sent command' ; break ; case IAMCPStatus . Suceeded : message = 'Succeeded command' ; break ; case IAMCPStatus . Failed : message = 'Failed command' ; break ; } return message ; } /**
         *
         */ protected validateParam ( signature ) { let result ; let param ; if ( this . _objectParams . hasOwnProperty ( signature . name ) ) { param = this . _objectParams [ signature . name ] ; } else { if ( this . _stringParamsArray . length > 0 ) { param = this . _stringParamsArray ; } else { return false ; } } if ( param === undefined ) { return false ; } result = signature . validation . resolve ( param , ( signature . key || signature . name ) ) ; if ( result !== false ) { signature . validation . resolved = true ; if ( typeof result === 'object' && result . hasOwnProperty ( 'raw' ) && result . hasOwnProperty ( 'payload' ) ) { signature . payload = result . payload ; signature . raw = result . raw ; } else { signature . payload = result ; } return true ; } else { return false ; } } /**
         *
         */ protected validateProtocolLogic ( ) { if ( ! this . protocolLogic ) { return true ; } let result ; for ( let rule of this . protocolLogic ) { result = rule . resolve ( this . paramProtocol ) ; this . paramProtocol = result ; } return true ; } /**
         *
         */ protected validateChannel ( ) { let result ; let validator = new PositiveNumberValidatorBetween ( 1 , 9999 ) ; let param ; if ( this . _objectParams . hasOwnProperty ( 'channel' ) ) { param = Number ( this . _objectParams [ 'channel' ] ) ; } else { param = NaN ; } result = validator . resolve ( param ) ; if ( result !== false ) { return Number ( result ) ; } return NaN ; } /**
         *
         */ protected validateLayer ( fallback ? ) { let result ; let validator = new PositiveNumberValidatorBetween ( 0 , 9999 ) ; let param ; if ( this . _objectParams . hasOwnProperty ( 'layer' ) ) { param = Number ( this . _objectParams [ 'layer' ] ) ; } else { param = fallback || NaN ; } result = validator . resolve ( param ) ; if ( result !== false ) { return Number ( result ) ; } return 0 ; } } /**
     *
     */ export function isIAMCPCommand ( object ) { for ( let prop in AbstractCommand . prototype ) { if ( object [ prop ] === undefined ) { return false ; } } return true ; } /**
     *
     */ export abstract class AbstractOrChannelOrLayerCommand extends AbstractCommand { /**
         *
         */ constructor ( params ? , context ? ) { super ( params , context ) ; let channel = this . validateChannel ( ) ; let layer = this . validateLayer ( ) ; if ( channel ) { this . _channel = channel ; if ( layer ) { this . _layer = layer ; } } } /**
         *
         */ get channel ( ) : number { return this . _channel || - 1 ; } /**
         *
         */ get layer ( ) : number { return this . _layer || - 1 ; } /**
         *
         */ get address ( ) : string { let address = '' ; if ( this . channel && ( this . channel > - 1 ) ) { address = this . channel . toString ( ) ; } else { return address ; } if ( this . layer && ( this . layer > - 1 ) ) { address = `${ address }-${ this . layer }` ; } return address ; } } /**
     *
     */ export abstract class AbstractChannelCommand extends AbstractCommand { /**
         *
         */ constructor ( params , context ? ) { super ( params , context ) ; let channel = this . validateChannel ( ) ; if ( channel ) { this . _channel = channel ; this . _layer = - 1 ; } else { throw new Error ( 'Needs channel' ) ; } } /**
         *
         */ get channel ( ) : number { return this . _channel || - 1 ; } /**
         *
         */ get layer ( ) : number { return - 1 ; } /**
         *
         */ get address ( ) : string { if ( this . channel ) { return this . channel . toString ( ) ; } else { return '' ; } } } /**
     *
     */ export abstract class AbstractLayerCommand extends AbstractCommand { /**
         *
         */ constructor ( params , context ? ) { super ( params , context ) ; let channel = this . validateChannel ( ) ; let layer = this . validateLayer ( ) ; if ( channel && layer ) { this . _channel = channel ; this . _layer = layer ; } else { throw new Error ( 'Needs both channel and layer' ) ; } } /**
         *
         */ get channel ( ) : number { return this . _channel || - 1 ; } /**
         *
         */ get layer ( ) : number { return this . _layer || - 1 ; } /**
         *
         */ get address ( ) : string { let address ; if ( this . channel && ( this . channel > - 1 ) ) { address = this . channel . toString ( ) ; } else { return '' ; } if ( this . layer && ( this . layer > - 1 ) ) { address = `${ address }-${ this . layer }` ; } else { return '' ; } return address ; } } /**
     *
     */ export abstract class AbstractChannelOrLayerCommand extends AbstractCommand { /**
         *
         */ constructor ( params , context ? ) { super ( params , context ) ; let channel = this . validateChannel ( ) ; let layer = this . validateLayer ( ) ; if ( channel ) { this . _channel = channel ; if ( layer ) { this . _layer = layer ; } } else { throw new Error ( 'Needs at least channel' ) ; } } /**
         *
         */ get channel ( ) : number { return this . _channel || - 1 ; } /**
         *
         */ get layer ( ) : number { return this . _layer || - 1 ; } /**
         *
         */ get address ( ) : string { let address ; if ( this . channel ) { address = this . channel . toString ( ) ; } else { return '' ; } if ( this . layer && ( this . layer > - 1 ) ) { address = `${ address }-${ this . layer }` ; } return address ; } } /**
     *
     */ export abstract class AbstractLayerWithFallbackCommand extends AbstractCommand { /**
         *
         */ constructor ( params , context ? ) { super ( params , context ) ; let channel = this . validateChannel ( ) ; let layer = this . validateLayer ( 0 ) ; if ( channel ) { this . _channel = channel ; this . _layer = layer ; } else { throw new Error ( 'Needs at least channel, layer will default to 0 if not specified' ) ; } } /**
         *
         */ get channel ( ) : number { return this . _channel || - 1 ; } /**
         *
         */ get layer ( ) : number { return this . _layer || - 1 ; } /**
         *
         */ get address ( ) : string { let address ; if ( this . channel ) { address = this . channel . toString ( ) ; } else { return '' ; } if ( this . layer && ( this . layer > - 1 ) ) { address = `${ address }-${ this . layer }` ; } return address ; } } /**
     *
     */ export abstract class AbstractLayerWithCgFallbackCommand extends AbstractCommand { /**
         *
         */ constructor ( params , context ? ) { super ( params , context ) ; let channel = this . validateChannel ( ) ; let layer = this . validateLayer ( 9999 ) ; if ( channel ) { this . _channel = channel ; this . _layer = layer ; } else { throw new Error ( 'Needs at least channel, layer will default to 9999 if not specified' ) ; } } /**
         *
         */ get channel ( ) : number { return this . _channel || - 1 ; } /**
         *
         */ get layer ( ) : number { return this . _layer || - 1 ; } /**
         *
         */ get address ( ) : string { let address ; if ( this . channel ) { address = this . channel . toString ( ) ; } else { return '' ; } if ( this . layer && ( this . layer > - 1 ) ) { address = `${ address }-${ this . layer }` ; } return address ; } } }