//apps.modbus_util.tools.converters переписанное на js


/*
  Преобразование данных

  Форматы:
    h       - шестнадцатиричное число
    hl      - последовательность байт, заданная шестнадцатеричными числами через запятую.
    d       - десятеричное число
    dl      - последовательность байт, заданная десятиричными числами через запятую.
    b       - двоичное число
    bl      - последовательность 8-битных чисел через запятую.
    ip      - адрес ip, 4 десятеричных числа через точку
    a       - строка ascii символов
    m       - смешанная (для вывода) - байты в шестнадцатеричном представлении с добавлением 
*/

const struct = require('python-struct');

function rstrip(val,chars=''){
    var out = val.replace(/\x00\u0000\0.*$/g, "")
    return out
}

function decode(fmt, val, flen=null){
    /*
        Преобразование val из формата, заданного в fmt в bytearray
        flen - размер, до которого нужно дополнить поле.
    */
    var func = FORMATS[fmt]||[null,null,null]
    func = func[0]
    if (func==null){
        throw String(`Unknown format ${fmt}`)
    }

    try{
        return func(val, flen)
    }catch (e){
        throw e
    }
}

function encode(fmt, val){
    /*
        Преобразование val из bytearray в формат, заданный в fmt.
    */
    var func = FORMATS[fmt]||[null,null,null]
    func = func[1]
    if (func==null){
        throw String(`Unknown format ${fmt}`)
    }

    try{
        return func(val)        
    }catch(e){
        throw e
    }
}

function formats_list(){
    /*
        Список кодов установленных форматов
    */
    l = Object.keys(FORMATS)
    l=l.sort()
    return l
}

function formats_descr(){
    /*
        список [(Код_формата, описание),]
    */
    var res = []
    for (var ll in formats_list()){
        res.push([ll, FORMATS[ll][2]])
    }
    return res
}

//======

function check_len(in_len, max_len = null){
    /*
        Выравнивает длину по границе 2х байт.
        Если задана max_len - ограничивает этим значением.
    */
    if (in_len == null){
        return max_len
    }

    var d = Math.floor(in_len/2)
    var r = in_len%2
    var ll = (d+r)*2
    if (max_len != null){
        var d = Math.floor(max_len/2)
        var r = max_len%2
        max_len = (d+r)*2
        if (ll>max_len){
            return max_len
        }else{
            return ll
        }
    }else{
        return ll
    }
}

function decode_h(val, flen=null){
    /*
       Преобразование h->bytearray
    */
    var flen = check_len(flen, 8)
    var out = struct.pack(">Q", parseInt(val).toString(16))
    if (flen!=null){
        out = out.slice(out.length-flen,out.length)
    }
    return out
}

function encode_h(val){
    /*
       Преобразование bytearray->h
    */ 
    var v = Buffer.concat([Buffer.from('00'.repeat(7),'hex'),val]).slice(val.length-1,val.length+7);
    //v = struct.unpack(">Q", (bytearray([0]*7)+val)[-8:])[0]
    var out = 0;
    for(var i=0;i<8;i+=1){
        out+=v[v.length-1-i]*Math.pow(256,i)
    }
    return '0x'+parseInt(out,16).toString(16)
}
function decode_hl(val, flen=None){
    /*
       Преобразование hl->bytearray
    */
    var out = val.split(',')
    var out_s = ''
    for (var i in out){
        out_s+=parseInt(out[i].trim(),16).toString(16)
    }
    return Buffer.from(out_s,'hex')
    //return bytearray([int(itm.strip(" \n\r\t"),16) for itm in val.split(",")])
}

function encode_hl(val){
    /*
       Преобразование bytearray->hl
    */
    var out = []
    for(var i in val){
        out.push('0x'+(parseInt(val[i],16).toString(16)))
    }
    return out.join(',')
    //return ",".join(["%02X" % (itm,) for itm in val])
}

function decode_d(val, flen=null){
    /*
       Преобразование d->bytearray
    */
    var flen = check_len(flen, 8)
    var out = Buffer.from(struct.pack(">Q", parseInt(val, 10)))
    if (flen!=null){
        out = out.slice(out.length-flen,out.length)
    }
    return out
}

function encode_d(val){
    /*
        Преобразование bytearray->d
    */ 
    var val_1 = Buffer.concat([Buffer.from('00'.repeat(7),'hex'),val])
    var v = struct.unpack(">Q", val_1.slice(val_1.length-8,val_1.length))[0]
    return String(v)
}


function decode_f(val, flen=null){
    /*
       Преобразование f->bytearray (float for Officer)
    */
    var s = struct.pack(">f", Number(val))
    return Buffer.concat([s.slice(2,4),s.slice(0,2)])
}

function encode_f(val){
    /*
       Преобразование bytearray->f  (float for Officer)
    */ 
    var d = Buffer.concat([val.slice(2,4),val.slice(0,2)])
    var v = struct.unpack(">f", d)[0]
    return String(v)
}

function decode_dl(val, flen=null){
    /*
       Преобразование dl->bytearray
    */
    var out = val.split(',')
    var out_b = Buffer.from('','hex')
    for (var i in out){
        var h_num = parseInt(out[i].trim(),10).toString(16)
        if (h_num.length%2>0){
            h_num = '0'+h_num
        }
        out_b = Buffer.concat([out_b,Buffer.from(h_num,'hex')])
    }
    return out_b
    //return bytearray([int(itm.strip(" \n\r\t"),10) for itm in val.split(",")])
}

function encode_dl(val){
    /*
       Преобразование bytearray->dl
    */
    var out = []
    for(var i=0;i<val.length;i+=1){
        out.push(String(parseInt(val[i],10)))
    }
    return out.join(',')
    //return ",".join(["%s" % (itm,) for itm in val])
}

function decode_b(val, flen=null){
    /*
        Преобразование b->bytearray
    */
    flen = check_len(flen, 8)
    var val1 = val
    if (typeof val == 'number'){
        val1 = val.toString(2)
    }
    var out = Buffer.from(struct.pack(">Q", parseInt(val1, 2)),'binary')
    if (flen!=null){
        out = out.slice(out.length-flen,out.length)
    }
    return out
}

function encode_b(val){
    /*
        Преобразование bytearray->b
    */ 
    var val1 = Buffer.concat([Buffer.from('00'.repeat(7),'hex'),val])
    var v = struct.unpack(">Q", val1.slice(val1.length-8,val1.length))[0]
    return v.toString(2)
}

function decode_bl(val, flen=null){
    /*
    Преобразование bl->bytearray
    */
    var val_a = val.split(',')
    var out = Buffer.from('','hex')
    for(var i in val_a){
        var itm = parseInt(val_a[i].trim(),2).toString(16)
        if (itm.length%2>0){
            itm = '0'+itm
        }
        out = Buffer.concat([out,Buffer.from(itm,'hex')])
    }
    return out
    //return bytearray([int(itm.strip(" \n\r\t"),2) for itm in val.split(",")])
}

function encode_bl(val){
    /*
       Преобразование bytearray->bl
    "*/
    var out=[]
    for (var i=0;i<val.length;i+=1){
        var str = '0'.repeat(8)+val[i].toString(2)
        out.push(str.slice(str.length-8,str.length))
    }
    return out.join(',')
    //return ",".join([("0"*7 + bin(itm)[2:])[-8:] for itm in val])
}

function decode_ip(val, flen=null){
    /*
       Преобразование ip->bytearray
    */
    ll = val.split(".")
    if (ll.length != 4){
        throw "Wrong IP fields count"
    }
    var out = Buffer.from('','hex')
    for(var i in ll){
        var itm = parseInt(ll[i].trim(),10).toString(16)
        if (itm.length%2!=0){
            itm = '0'+itm
        }
        out = Buffer.concat([out,Buffer.from(itm,'hex')])
    }
    return out;
    //return bytearray([int(itm) for itm in ll])
}

function encode_ip(val){
    /*
       Преобразование bytearray->ip
    */ 
    if (val.length != 4){
        throw "Wrong IP fields count"
    }
    var out = []
    for (var i=0; i< val.length; i+=1){
        out.push(val[i])
    }
    return out.join('.')
    //return ".".join(["%s" % (itm,) for itm in val])
}

function decode_a(val, flen=null){
    /*
       Преобразование a->bytearray
    */

    res = Buffer.from(val,'ascii')
    lr = res.length
    if (flen==null){
        flen = check_len(flen, lr)
    }else{
        flen = check_len(flen)
    }

    if (flen!=null){
        if (flen>lr){
            res = Buffer.concat([res,Buffer.from('00'.repeat(flen-lr),'hex')])
        }else{
            res = res.slice(0,flen)
        }
    }
    return res
}

function encode_a(val){
    /*
       Преобразование bytearray->a
    */ 
    return rstrip(String(val))
}

/*
def decode_m(val, flen=None):
    """
       Преобразование m->bytearray
    """

def encode_m(val):
    """
       Преобразование bytearray->m
       32..126
    """ 
    res = []
    for itm in val:
        if 31<itm<127:
            res.append("%02X|%s|" % (itm, chr(itm)))
        else:
            res.append("%02X| |" % (itm,))

    return ", ".join(res)

*/

const FORMATS = {
    "h" :[decode_h, encode_h, "шестнадцатиричное число"],
    "hl":[decode_hl, encode_hl, "последовательность байт, заданная шестнадцатеричными числами через запятую."],
    "d" :[decode_d, encode_d, "десятеричное число"],
    "dl":[decode_dl, encode_dl, "последовательность байт, заданная десятиричными числами через запятую."],
    "b" :[decode_b, encode_b, "двоичное число"],
    "f" :[decode_f, encode_f, "float в специальном формате"],
    "bl":[decode_bl, encode_bl, "последовательность 8-битных чисел через запятую."],
    "ip":[decode_ip, encode_ip, "адрес ip, 4 десятеричных числа через точку"],
    "a" :[decode_a, encode_a, "строка ascii символов"],
    //"m" :[decode_m, encode_m, "смешанная (для вывода) - байты в шестнадцатеричном представлении с добавлением"],
    }

module.exports = {encode,decode,formats_list}