<?php
/*
* track.php
* http://tasuke.dna.affrc.go.jp/
*
* Author: Ryutaro Itoh
*
* Copyright (c) 2013 National Institute of Agrobiological Sciences   
*
*/

require '../conf/config.php';
require './common.php';
require './commonDB.php';
////////////////////////////////// Connecting with DB
if( !$conn = new mysqli($host, $user, $pswd, $db)) {
    error_log("Connection failed.\n");
    exit;
}

class TrackClass
{
  public $seq = NULL;
  public $id = NULL;
  public $name = NULL;
  public $pos = NULL;
  public $end = NULL;
  public $len = NULL;
  public $strand = NULL;
  public $others = NULL;
  public $type = NULL;

  function __construct($_seq, $_id, $_name, $_pos, $_end, $_len, $_strand, $_others, $_type) {
    $this->seq = $_seq;
    $this->id = $_id;
    $this->name = $_name;
    $this->pos = $_pos;
    $this->end = $_end;
    $this->len = $_len;
    $this->strand = $_strand;
    $this->others = $_others;
    $this->type = $_type;
  }
}

$reservedTracks = array("Primer3 Result" => True, "Blast Result" => True);

////////////////////////////////// Parameters
$prm_Tracks=array();
(isset($_POST['prm_Zoom']) && !empty($_POST['prm_Zoom'])) ? $prm_Zoom=$_POST['prm_Zoom']:returnError("Error");
(isset($_POST['prm_Chr']) && !empty($_POST['prm_Chr'])) ? $prm_Chr=$_POST['prm_Chr']:returnError("Error");
(isset($_POST['prm_Pos']) && !empty($_POST['prm_Pos'])) ? $prm_Pos=$_POST['prm_Pos']:returnError("Error");
(isset($_POST['prm_Block']) && !empty($_POST['prm_Block'])) ? $prm_Block=$_POST['prm_Block'] : returnError("Error");
(isset($_POST['prm_Tracks']) && !empty($_POST['prm_Tracks'])) ? $prm_Tracks=$_POST['prm_Tracks'] : returnError("Error");
if(preg_match("/\;|\||\&|\`|\(|\)|\<|\>|\*|\?|\{|\}|\[|\]|\!/",$prm_Zoom)) {
	$prm_Zoom = "1k";
}
if(!_validate_chrs($conn,$prm_Chr)){_stopError("||Invalid value");}
$prm_Pos = (int)$prm_Pos;
$prm_Block = (int)$prm_Block;
for($i=0;$i<count($prm_Tracks);$i++) {
	if(array_key_exists($prm_Tracks[$i], $reservedTracks)) { continue; }
	if(!_validate_each_tracks($conn,$prm_Tracks[$i])) { _stopError("||Invalid value"); }	// Heavy process!
//	if(!_validate_each_tracks($conn,$prm_Tracks[$i]) && $prm_Tracks[$i] != "Primer3 Result" && $prm_Tracks[$i] != "Blast Result"){_stopError("||Invalid value");}
}
$db_range_start=$prm_Pos*_cvtZoom($prm_Zoom)-_cvtZoom($prm_Zoom);
$db_range_end=($prm_Pos+$prm_Block)*_cvtZoom($prm_Zoom);

///////////////////////////////////////////////////////////////////////////////
// Tracks
///////////////////////////////////////////////////////////////////////////////
$rtnStringArray = array();
$track2floor = array();
for($i=0;$i<count($prm_Tracks);$i++) {
	$rtnStringArray[$prm_Tracks[$i]] = array();
	$track2floor[$prm_Tracks[$i]] = array('a1' => 0, 'a2' => 0, 'a3' => 0);
}

$query = "SELECT id,name,pos,end+1,(end-pos+1),strand,others,track,parent,type,seq FROM sys_track WHERE chr= ? and end+1 > ? and pos < ?";
//$query = "SELECT id, name, pos, end+1, (end-pos+1), strand, others FROM sys_track WHERE track= ? and chr= ? and parent=1 and end+1 > ? and pos < ? order by pos";
//$sql_params = array('sii', $prm_Chr, $db_range_start, $db_range_end);
$sql_params_pat = 'sii';
$sql_params_vals = array($prm_Chr, $db_range_start, $db_range_end);
if(count($prm_Tracks) > 0) {
	$sql_tracks = str_repeat("?,", count($prm_Tracks));
	$query .= " and track in (". preg_replace('/,$/', '', $sql_tracks). ")";
	for($i=0; $i<count($prm_Tracks); $i++) {
		$sql_params_pat .= 's';
		$sql_params_vals[] = $prm_Tracks[$i];
	}
}
$params = array();
$params[] = $sql_params_pat;
for($i=0; $i<count($sql_params_vals); $i++) {
	$params[] = &$sql_params_vals[$i];
}
$query .= " order by pos";
$stmt = $conn->stmt_init();
$stmt->prepare($query);
call_user_func_array(array($stmt, 'bind_param'), $params);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($rowN0,$rowN1,$rowN2,$rowN3,$rowN4,$rowN5,$rowN6,$rowN7,$rowN8,$rowN9, $rowN10);

$buf = array();	// 'track' -> ids[] -> {'parent'->TrackClass, 'subs'->TrackClass[]}
$noIdHead = '@@noId@@';
while ($stmt->fetch()) {
  $idKey = $rowN0;
  if(!$rowN0) $idKey = $noIdHead. $rowN10;

  if(!array_key_exists($rowN7, $buf)) $buf[$rowN7] = array();
  if(!array_key_exists($idKey, $buf[$rowN7])) $buf[$rowN7][$idKey] = array('parent' => NULL, 'subs' => array());

  $cls = new TrackClass($rowN10,$rowN0,$rowN1,$rowN2,$rowN3,$rowN4,$rowN5,$rowN6,$rowN9);
  if($rowN8 == 1) {
    $buf[$rowN7][$idKey]['parent'] = $cls;
  } else if($rowN8 == 0) {
    $buf[$rowN7][$idKey]['subs'][] = $cls;
  }
}

$subquery = "SELECT id,name,pos,end+1,(end-pos+1),strand,others,track,parent,type,seq from sys_track where track=? and parent=0 and chr=? and pos>=? and end<=? order by pos";
$stmtSub = $conn->stmt_init();
$stmtSub->prepare($subquery);

$rtnString="";
foreach ($prm_Tracks as $track) {
  $rtnString .= "[";
  if(!array_key_exists($track, $buf)) {
    $rtnString .= "]|";
    continue;
  }

  foreach($buf[$track] as $idkeyNotUse => $parentSubs) {	// PHP hash keeps order of insertion
    // parent
    $parent = $parentSubs['parent'];
    $a1 = &$track2floor[$track]['a1'];
    $a2 = &$track2floor[$track]['a2'];
    $a3 = &$track2floor[$track]['a3'];

    $dest_url=$parent->id;
    $pos_Zoom = (int)$parent->pos/_cvtZoom($prm_Zoom);
    $end_Zoom = (int)$parent->end/_cvtZoom($prm_Zoom);
    if ( $prm_Zoom == "1b" ) {
            $rs = $pos_Zoom - $prm_Pos;
            $re = $end_Zoom - $prm_Pos;
            $p1=(int)$pos_Zoom - $prm_Pos;
            if ((int)$parent->end % _cvtZoom($prm_Zoom)){
                $p=(int)$end_Zoom - $prm_Pos+1;
            } else {
                $p=(int)$end_Zoom - $prm_Pos;
            }
    }else{
            $rs = $pos_Zoom - $prm_Pos+1;
            $re = $end_Zoom - $prm_Pos+1;
            $p1=(int)$pos_Zoom - $prm_Pos+1;
            if ((int)$parent->end % _cvtZoom($prm_Zoom)){
                $p=(int)$end_Zoom - $prm_Pos+2;
            } else {
                $p=(int)$end_Zoom - $prm_Pos+1;
            }
    }
    if ( $p1 > $a1 || $a1 == null ) {
            $h=1;
            $a1=$p;
    } else if ( $p1 > $a2 || $a2 == null ) {
            $h=2;
            $a2=$p;
    } else if ( $p1 > $a3 || $a3 == null ) {
            $h=3;
            $a3=$p;
    } else {
            $h=4;
    }

    $extag = $external_link_tag_gff;
    if(isset($external_sites) && array_key_exists($rowN7, $external_sites)) {
	$extag = $external_sites[$rowN7]['tag_gff'];
    }
    if($extag != "ID" and $extag != ""){
            $str_array = explode(";",$parent->others);
            $str_array_cnt = count($str_array);
            for ($a=0; $a < $str_array_cnt; $a++){
                $tag_val = explode("=",$str_array[$a]);
                if($tag_val[0] == $extag){
                    $dest_url=$tag_val[1];
                    break;
                }else{
                    $dest_url="";
                }
            }
    }

    // trim feature string.
/*
    $others = "";
    if($parent->type=='transcript' || $parent->type=='gene' || $parent->type=='mRNA') {
      $others = $parent->others;
      if(strlen($others) > 88) {
        $others = substr($others, 0, 85);
        $others .= '...';
      }
      $others = addslashes($others);
    }
*/
//    $arrStr = "\"id\":\"". $parent->id. "\",\"name\":\"". $parent->name. "\",\"pos\":\"". (int)$parent->pos. "\",\"length\":\"". (int)$parent->len. "\",\"strand\":\"". $parent->strand. "\",\"s\":\"". $p1. "\",\"e\":\"". $p. "\",\"h\":\"". $h. "\",\"rs\":\"". $rs. "\",\"re\":\"". $re. "\",\"ln\":\"". $dest_url. "\"";
//    $arrStr = "\"id\":\"". $parent->id. "\",\"name\":\"". $parent->name. "\",\"pos\":\"". (int)$parent->pos. "\",\"length\":\"". (int)$parent->len. "\",".
//      "\"strand\":\"". $parent->strand. "\",\"s\":\"". $p1. "\",\"e\":\"". $p. "\",\"h\":\"". $h. "\",\"rs\":\"". $rs. "\",\"re\":\"". $re. "\",".
//      "\"ln\":\"". $dest_url. "\",\"sq\":\"". $parent->seq. "\"";
      $arrStr = "\"id\":\"". $parent->id. "\",\"name\":\"". $parent->name. "\",\"pos\":\"". (int)$parent->pos. "\",\"length\":\"". (int)$parent->len. "\",".
	"\"strand\":\"". $parent->strand. "\",\"s\":\"". $p1. "\",\"e\":\"". $p. "\",\"h\":\"". $h. "\",".
	"\"ln\":\"". $dest_url. "\",\"sq\":\"". $parent->seq. "\"";

    // subs
    $subStr="";
    if ( $parent->id != "" ) {
      $subs = $parentSubs['subs'];
      $subs_cnt = count($subs);
      if($subs_cnt==0 && $parent->pos < $db_range_start && $parent->end > $db_range_end) {
          // If the transcript cannot get even one exon, the drawing will be incorrect and the data will be complemented. 
          $stmtSub->bind_param("ssii", $track, $prm_Chr, $parent->pos, $parent->end);
          $stmtSub->execute();
          $stmtSub->store_result();
          $stmtSub->bind_result($s_id, $s_name, $s_pos, $s_end, $s_len, $s_strand, $s_others, $s_track, $s_parent, $s_type, $s_seq);
          while ($stmtSub->fetch()) {
              $cls = new TrackClass($s_seq, $s_id, $s_name, $s_pos, $s_end, $s_len, $s_strand, $s_others, $s_type);
              $subs[] = $cls;
          }
      }
      $subs_cnt = count($subs);
      if ( $subs_cnt > 0 ) {
          $subStr .= ",\"t\":\"";
          for($j=0;$j<$subs_cnt;$j++){
                $s = ($subs[$j]->pos - $parent->pos) / $parent->len *100;
                $l = $subs[$j]->len / $parent->len * 100;
                if ( strstr(strtolower($subs[$j]->type), "utr") ) {$t="u";}
                else if ( strstr(strtolower($subs[$j]->type), "cds") ) {$t="c";}
                else if ( strstr(strtolower($subs[$j]->type), "exon") ) {$t="e";}
                else {$t="a";}
                $subStr .= $t. "-". $s. "-". $l. ";";
          }
          $subStr = preg_replace('/;$/', '', $subStr);
          $subStr .= "\"";
      }
    }
    $rtnString .= "{". $arrStr. $subStr. "},";
  }
  $rtnString = preg_replace('/,$/', '', $rtnString);

  $rtnString .= "]|";
}
$rtnString = preg_replace('/\|$/', '', $rtnString);

$stmt->close();
$stmtSub->close();

///////////////////////////////////////////////////////////////////////////////
// Loading FASTA during zoom is '1b'
///////////////////////////////////////////////////////////////////////////////
if ( $prm_Zoom == '1b' ) {
    $prm_Chr = $conn->real_escape_string($prm_Chr);

    $table = getSerialTableByColumn($conn, $db, "sys_fasta", $prm_Chr. "_f");
    $queryFa = "SELECT `". $prm_Chr. "_f` FROM ". $table. " WHERE pos>=? AND pos<? ";    
//    $queryFa = "SELECT `". $prm_Chr. "_f` FROM sys_fasta WHERE pos>=? AND pos<? ";

    $stmtFa = $conn->stmt_init();
    $stmtFa->prepare($queryFa);
    $paramFa1=($prm_Pos+$prm_Block);
    $stmtFa->bind_param("ii", $prm_Pos, $paramFa1);  
    $stmtFa->execute();
    $stmtFa->store_result();
    $stmtFa->bind_result($rowF0);
    while ($stmtFa->fetch()) {
        $arrF[] = "{\"f\":\"".$rowF0."\"}";
    }
    $stmtFa->free_result();
    $stmtFa->close();
    $rtnString=$rtnString."|[";
    for($i=0;$i<count($arrF);$i++){
	$rtnString .= $arrF[$i];
	if($i<count($arrF)-1) {$rtnString .= ",";}
    }
    $rtnString .= "]";
} else {
    $rtnString .= "|[]";
}
mysqli_close($conn);

//file_put_contents("/tmp/track_php_new", $rtnString);
echo $rtnString;

function returnError($str){
    echo $str;
}

function _stopError($str){
    echo $str;
    exit;
}

function _cvtZoom($str) {
    preg_match("/^[0-9]+/", $str, $r1);
    preg_match('/[b,k]$/', $str, $r2);
    $v=$r1[0];
    if($r2[0] == "b"){
        $r=1*(int)$v;
    } else {
        $r=1000*(int)$v;
    }
    return (int)$r;
}

function _validate_chrs($conn, $prm_Chr){
    $flag = false;
    $query = "select seq from sys_chromosome where id=? limit 1";
    $stmt = $conn->stmt_init();
    $stmt->prepare($query);
    $stmt->bind_param("s", $prm_Chr);
    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result($row0);
    while ($stmt->fetch()) {
        $flag = true;
    }
    $stmt->free_result();
    $stmt->close();
    if($flag){
       return true;
    }else{
       return false;
    }
}

function _validate_each_tracks($conn,$list){
	$flag = false;
	$query = "SELECT track FROM sys_track where track = ? limit 1";
        $stmt = $conn->stmt_init();
        $stmt->prepare($query);
        $stmt->bind_param("s", $list);
        $stmt->execute();
        $stmt->store_result();
        $stmt->bind_result($row0);
        while ($stmt->fetch()) {
            $flag = true;
        }
        $stmt->free_result();
        $stmt->close();
        if($flag){
           return true;
        }else{
           return false;
        }
}
?>

