const fs = require('fs');
const path = require('path');

module.exports = {
  getPermissions: function(clientInfo, token){
    return token == "secret_token 321";
  },

  parseClientInfo: function(ws, req){
    var clientInfo = {
      "type": "",
      "devicename": "",
      "url": "",
      "allowedToUpload": false,
      "allowedToListen": false,
      "idstr": "",
      "timeOfConnect": new Date() / 1000
    };

    let url = req.url;
    let name = req.headers["devicename"];
    let token = req.headers["apitoken"];
    let type = req.headers["type"];

    clientInfo.url = url;
    
    // determine type of connection
    switch(type){
      case "device": clientInfo.type = "device"; break;
      // case "web": clientInfo.type = "client"; break;
      // case "app": clientInfo.type = "app"; break;
      default:
        // clientInfo.type = "unrecognized device type";
        clientInfo.type = "client";
        break;
    }

    // apply name
    if(type == "device"){
      clientInfo.devicename = (name === undefined ? "nameless device" : name);
    }
    else{
      clientInfo.devicename = "-";
    }

    // give permissions
    clientInfo.allowedToListen = true;
    clientInfo.allowedToUpload = this.getPermissions(clientInfo, token);

    clientInfo.idstr = clientInfo.type == "client" ? "client" + Math.round(10000 * Math.random()) : clientInfo.type + "/" + clientInfo.devicename

    return clientInfo;
  },

  writeInFormat: function(varName, data){
    var varNameLen = varName.length
    var dataLen = data.length

    var totalLength = 8 + varNameLen

    var retBuf = Buffer.alloc(totalLength);

    retBuf.writeUInt32BE(varNameLen, 0);
    retBuf.write(varName, 4, varNameLen, 'utf-8');
    retBuf.writeUInt32BE(dataLen, 4+varNameLen);

    return Buffer.concat([retBuf, data]);
  },

  // readInFormat: function(data){
  //   var variables = [];
  //   while (data.length > 0){
  //     var varNameLen = data.readUInt32BE(0);
  //     var varName = data.toString('utf-8', 4, 4+varNameLen);

  //     var dataLen = data.readUInt32BE(4+varNameLen);
  //     var dataBuf = data.slice(8+varNameLen, 8+varNameLen+dataLen);

  //     variables.push({
  //       "varName": varName,
  //       "data": dataBuf
  //     })

  //     data = data.slice(8+varNameLen+dataLen, data.length);
  //   }
  //   return variables;
  // },
  readInFormat: function(data){
    var variables = {};
    while (data.length > 0){
      var varNameLen = data.readUInt32BE(0);
      var varName = data.toString('utf-8', 4, 4+varNameLen);

      var dataLen = data.readUInt32BE(4+varNameLen);
      var dataBuf = data.slice(8+varNameLen, 8+varNameLen+dataLen);

      variables[varName] = dataBuf;

      data = data.slice(8+varNameLen+dataLen, data.length);
    }
    return variables;
  },

  saveToFile: function(filename, content){
    fs.writeFile(filename, content, err => {
      if(err){
        console.error(err);
      }
    });
  },

  readFilesInDir: function(dir){
    const isFile = fileName => {
      return fs.lstatSync(fileName).isFile();
    };
    
    let files = fs.readdirSync(dir)
      .map(fileName => {
        return path.join(dir, fileName);
      })
      .filter(isFile);
    
    return files;
  },

  readFootageMetadataInDir: function(dir){
    let files = this.readFilesInDir(dir);

    let timeStamps = files.map(fn => fn.slice(fn.lastIndexOf('_')+1, fn.lastIndexOf('.')));
    let types = files.map(fn => fn.slice(fn.lastIndexOf('/')+1, fn.lastIndexOf('_')));

    // console.log(timeStamps);
    // console.log(types);

    const zip = (a,b,c) => a.map((k,i) => [k, b[i], c[i]]);

    let zipped = zip(types, timeStamps, files);
    // console.log(zipped);

    const mapToType = (arr) => arr.map(x =>{
      return {
        "type": x[0],
        "other": x.slice(1)
      };
    });

    let mappedToType = mapToType(zipped);
    // console.log(mappedToType);
    
    const groupByAndPutInFormat = function(xs, key) {
      return xs.reduce(function(rv, x) {
        (rv[x[key]] = rv[x[key]] || []).push({
          "timestamp": parseFloat(x.other[0]),
          "filename": x.other[1]
        });
        return rv;
      }, {});
    };

    let footageGrouped = groupByAndPutInFormat(mappedToType, "type");
    // console.log(footageGrouped);

    // let minTimestamp = 

    return footageGrouped;
  },

  _closestLessThan: function(arr, num){
    let arr2 = arr.map(x => [x, x - num]).filter(x => x[1] < 0);
    return arr2.length == 0 ? arr.reduce((a,b) => a > b ? a : b) : arr2.reduce(function(prev, curr){
      return prev[1] > curr[1] ? prev : curr;
    })[0];
  }

  // findClosestInFootage: function(footageMetadata){
  // }

  // readInFormat: function(data){
  //   var variables = {};
  //   var i = 0
  //   while (i < data.byteLength){
  //     var varNameLen = new DataView(data, i, 4).getUint32(0, false);
  //     var dataLen = new DataView(data, i+4+varNameLen, 4).getUint32(0, false);

  //     var varName = new TextDecoder("utf-8").decode(new Uint8Array(data, i+4, varNameLen));
      
  //     var dataBuf2 = new ArrayBuffer(dataLen);
  //     var dataBuf = new Uint8Array(dataBuf2);
  //     dataBuf.set(new Uint8Array(data, i+8+varNameLen, dataLen), 0);

  //     variables[varName] = dataBuf2;

  //     i += 8 + varNameLen + dataLen
  //   }
  //   return variables;
  // }
}

if(false){ // delete later
  var x = "something here";
  var y = 654321;

  var bufY = Buffer.alloc(4);
  bufY.writeInt32BE(y, 0);

  var xinFormat = module.exports.writeInFormat("var1", Buffer.from(x, 'utf-8'));
  var yinFormat = module.exports.writeInFormat("var2", bufY);

  // console.log(xinFormat.toString('utf-8'));
  // console.log(yinFormat.toString('utf-8'));

  var total = Buffer.concat([xinFormat, yinFormat]);

  // var data = module.exports.readInFormat(xinFormat);
  var data = module.exports.readInFormat(total);

  console.log(data);
}


if(false){ // delete later
  // module.exports.readFootageMetadataInDir("./fake_camera_footage/1/");

  let x = module.exports._closestLessThan([1, 2, 3, 4, 5, 6], 8);
  console.log(x);
}
