var express =   require("express");
var fs = require('fs');
var bodyParser =    require("body-parser");
var multer  =   require('multer');
var exec = require('child_process').exec;
var app =   express();

app.use(bodyParser.json());
app.use(express.static('public'))
app.use(express.static('files'))
app.use('/public', express.static(__dirname + '/public'));

// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded());

// Parse JSON bodies (as sent by API clients)
app.use(express.json());

var storage = multer.diskStorage({
  destination: function (req, file, callback) {
    callback(null, './public/uploads');
  },
  filename: function (req, file, callback) {
    callback(null, file.originalname);
  }
});
var upload = multer({ storage : storage }).array('pdbs',10);

app.get('/',function(req,res){
      res.sendFile(__dirname + "/Index.html");
});




function findLoops(res, wantedProtein){
  //find if protein file is in archdb index
  fs.readFile(__dirname + "/public/archdb_index.txt",'utf8', function (err, data) {
    if (err) throw err;
    if(data.includes(wantedProtein.toUpperCase())){
     // console.log(wantedProtein.toUpperCase())
    } else {
      res.send("No loops for the protein " + wantedProtein);
      return res.end("err");
    }
  });

  //if it is, return proteins
  let loops = [];
  let lines = [];
  fs.readFile(__dirname + "/public/archdb.mini.tab",'utf8', function(err,contents){
    if (contents !== undefined){
      lines = contents.split('\n');
      lines.forEach( line =>{
        let proteinChain = line.trim().split(/\s+/)[1];
        if (proteinChain === wantedProtein.toUpperCase()){
          loops.push(line);
        }
      })
    }
    res.send(loops);
  })
}

function findBfactors(res, wantedPDBfile){
  let lines = [];
  let atoms = [];
  fs.readFile(__dirname+"/public/uploads/"+wantedPDBfile,'utf8', function(err,contents){
    if (contents !== undefined){
      lines = contents.split('\n');
      lines.forEach( line =>{
        let proteinAtom = line.trim().split(/\s+/);
        if (proteinAtom[0] === "ATOM" || proteinAtom[0] === "HETATM"){
          atoms.push(proteinAtom);
        }
      })
    }
    else{
      console.log('ERR file not found');
    }
    res.send(atoms);
  })
}


app.get('/loops', function(req,res){
  findLoops(res,req.query.name);
})

app.get('/bfactors', function(req, res){
  findBfactors(res, req.query.name);
})

app.post('/api/pdb',function(req,res){
  upload(req,res,function(err) {
    //console.log(req.body);
    //console.log(req.files);

    var bodyList = "";

    for (var i = 0; i < req.files.length; i++) {
      bodyList += req.files[i].originalname + "\n";
    }
    //console.log(bodyList);
    calculateAlignment(bodyList, err, res);
  });
        
});

app.post("/api/wannabepdbs", function (req, res, err) {

    // console.log(req.body.pdbs);
    var pdbs = req.body.pdbs.replace(/\s/g, '').split(',');
    var bodyList = "";
    filePath = __dirname + '/public/uploads/list.txt';

    var countDownloadedPDBs = 0;

    var format = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/;

    for (var i = 0; i < pdbs.length; i++) {
      bodyList += pdbs[i] + ".pdb\n";
      const pms = new Promise((resolve, reject) => {
        

          //remove wrong quadruplets
          if(pdbs[i].length != 4 || format.test(pdbs[i])) 
            return res.end(pdbs[i] + " is not a valid PDB code.");

          exec("wget https://files.rcsb.org/download/" + pdbs[i] + ".pdb" + " -O ./public/uploads/" + pdbs[i] + ".pdb", 
               function(error, stdout, stderr){              
                  // console.log("Stderr: " + stderr);
                  // console.log("Strout: " + stdout);
                  // console.log("Error: " + error);

                  if (error) {
                    console.log(stderr);
                    var P = stderr.split(".pdb")[0].slice(-4);
                    var E = stderr.split("ERROR").pop();
                    reject("Inserted PDB quadruple " + P + " resulted with following error: " + E);
                    // return res.end(pdbs[i] + " could not be downloaded.");
                  }
                  // console.log(stdout);
                  // res.end("Success");
                  resolve('Success'); 
          });  
      }).then(
        function resolveDownloadedPDBs(){
          if(++countDownloadedPDBs === pdbs.length) {
            // console.log(pdbs.length);
            // console.log(countDownloadedPDBs);
            calculateAlignment(bodyList, err, res);
          }
        }
        
      ).catch((error) => {
        return res.end(error);
        done();
      });
    }
  
});

app.get('/download', function(req, res){
  console.log("Creating ZIP file...");
  var tozip = req.query.proteins.replace(/\s/g, '').replace(/,/g, '');
  if(tozip === "1cqw2had") res.send("/public/demo/demo.zip");
  const pms = new Promise((resolve, reject) => {
      exec("zip -r -X " + __dirname + "/public/uploads/" + tozip + ".zip " + __dirname + "/public/uploads/" + tozip, 
           function(error, stdout, stderr){

        if (error) {
          console.log(stderr);
          return res.end(stderr);
        }
        console.log(stdout);
        resolve("Success");
      });
  }).then(
    function prepareToDownload(){
      var fileName = "/public/uploads/" + tozip + ".zip";
      res.send(fileName);
  });
  
});

function calculateAlignment(bodyList, err, res){
  filePath = __dirname + '/public/uploads/list.txt';
  const pms = new Promise((resolve, reject) => {

      fs.writeFile(filePath, bodyList, function(err) {
        if(err) {
            return console.log(err);
            reject(err);
        }
        console.log("The file was saved!");
        resolve('Success');
      });
    }         
  ).then(
    function execPipe(){
      console.log("Executing pipe...");
      exec("bash ./public/uploads/pipe.sh", function(error, stdout, stderr){
        // console.log("Stderr: " + stderr);
        // console.log("Strout: " + stdout);
        // console.log("Error: " + error);

        if (error) {
          console.log(stderr);
          return res.end(stderr);
        }
        console.log(stdout);
        res.end("Success");
      });
    }
  ).catch((error) => {
    return res.end(error);
    done();
  });
}

app.listen(3000,function(){
    console.log("Working on port 3000");
});