import BitArray from '../../common/BitArray' ; import Token from './Token' ; import * as TokenHelpers from './TokenHelpers' ; import * as C from './EncoderConstants' ; import * as LatchTable from './LatchTable' ; import * as ShiftTable from './ShiftTable' ; import StringUtils from '../../common/StringUtils' ; import { int , Deque } from '../../../customTypings' ; /**
 * State represents all information about a sequence necessary to generate the current output.
 * Note that a state is immutable.
 */ export default class State { static INITIAL_STATE : State = new State ( C . EMPTY_TOKEN , C . MODE_UPPER , 0 , 0 ) ; private mode : int ; private token : Token ; private binaryShiftByteCount : int ; private bitCount : int ; private constructor ( token , mode , binaryBytes , bitCount ) { this . token = token ; this . mode = mode ; this . binaryShiftByteCount = binaryBytes ; this . bitCount = bitCount ; } getMode ( ) { return this . mode ; } getToken ( ) { return this . token ; } getBinaryShiftByteCount ( ) { return this . binaryShiftByteCount ; } getBitCount ( ) { return this . bitCount ; } latchAndAppend ( mode , value ) { let bitCount = this . bitCount ; let token = this . token ; if ( mode !== this . mode ) { let latch = LatchTable . LATCH_TABLE [ this . mode ] [ mode ] ; token = TokenHelpers . add ( token , latch & 0xffff , latch >> 16 ) ; bitCount += latch >> 16 ; } let latchModeBitCount = mode === C . MODE_DIGIT ? 4 : 5 ; token = TokenHelpers . add ( token , value , latchModeBitCount ) ; return new State ( token , mode , 0 , bitCount + latchModeBitCount ) ; } shiftAndAppend ( mode , value ) { let token = this . token ; let thisModeBitCount = this . mode === C . MODE_DIGIT ? 4 : 5 ; token = TokenHelpers . add ( token , ShiftTable . SHIFT_TABLE [ this . mode ] [ mode ] , thisModeBitCount ) ; token = TokenHelpers . add ( token , value , 5 ) ; return new State ( token , this . mode , 0 , this . bitCount + thisModeBitCount + 5 ) ; } addBinaryShiftChar ( index ) { let token = this . token ; let mode = this . mode ; let bitCount = this . bitCount ; if ( this . mode === C . MODE_PUNCT || this . mode === C . MODE_DIGIT ) { let latch = LatchTable . LATCH_TABLE [ mode ] [ C . MODE_UPPER ] ; token = TokenHelpers . add ( token , latch & 0xffff , latch >> 16 ) ; bitCount += latch >> 16 ; mode = C . MODE_UPPER ; } let deltaBitCount = this . binaryShiftByteCount === 0 || this . binaryShiftByteCount === 31 ? 18 : this . binaryShiftByteCount === 62 ? 9 : 8 ; let result = new State ( token , mode , this . binaryShiftByteCount + 1 , bitCount + deltaBitCount ) ; if ( result . binaryShiftByteCount === 2047 + 31 ) { result = result . endBinaryShift ( index + 1 ) ; } return result ; } endBinaryShift ( index ) { if ( this . binaryShiftByteCount === 0 ) { return this ; } let token = this . token ; token = TokenHelpers . addBinaryShift ( token , index - this . binaryShiftByteCount , this . binaryShiftByteCount ) ; return new State ( token , this . mode , 0 , this . bitCount ) ; } isBetterThanOrEqualTo ( other ) { let newModeBitCount = this . bitCount + ( LatchTable . LATCH_TABLE [ this . mode ] [ other . mode ] >> 16 ) ; if ( this . binaryShiftByteCount < other . binaryShiftByteCount ) { newModeBitCount += State . calculateBinaryShiftCost ( other ) - State . calculateBinaryShiftCost ( this ) ; } else if ( this . binaryShiftByteCount > other . binaryShiftByteCount && other . binaryShiftByteCount > 0 ) { newModeBitCount += 10 ; } return newModeBitCount <= other . bitCount ; } toBitArray ( text ) { let symbols = [ ] ; for ( let token = this . endBinaryShift ( text . length ) . token ; token !== null ; token = token . getPrevious ( ) ) { symbols . unshift ( token ) ; } let bitArray = new BitArray ( ) ; for ( const symbol of symbols ) { symbol . appendTo ( bitArray , text ) ; } return bitArray ; } Override public toString ( ) { return StringUtils . format ( '%s bits=%d bytes=%d' , C . MODE_NAMES [ this . mode ] , this . bitCount , this . binaryShiftByteCount ) ; } private static calculateBinaryShiftCost ( state ) { if ( state . binaryShiftByteCount > 62 ) { return 21 ; } if ( state . binaryShiftByteCount > 31 ) { return 20 ; } if ( state . binaryShiftByteCount > 0 ) { return 10 ; } return 0 ; } }