{% extends base.html %}

{% block title %}Transaction Log{% end %}

{% block includes %}
<script type="text/javascript" charset="utf-8" src="{{ static_url('js/jquery.dataTables.min.js') }}"></script>
<script type="text/javascript" charset="utf-8" src="{{ static_url('js/dataTables.bootstrap.js') }}"></script>
<script type="text/javascript" charset="utf-8" src="{{ static_url('js/jquery.highlight.js') }}"></script>
<link href="{{ static_url('css/dataTables.bootstrap.css') }}" rel="stylesheet">
<style type="text/css">

.top-buffer { margin-bottom:30px; }
.check {}
.launch-modal {margin: 20px;}
.modal-dialog-center{
  width: 320px;
  margin: 0;
  position: absolute;
  top: 35%;
  left: 42%;
}
.clear { clear: both; height: 80px; }

.scrollablePre {
  overflow: auto;
  word-wrap: normal;
  overflow-wrap: normal;
  white-space: pre;
}

.highlight {
  background-color: #FFFF88
}
</style>

{% end %}


{% block content %}
<div id="wrap">
  <div class="container">
    <div class="row top-buffer">
      <div class="col-md-12">
        <div class="col-md-12">
          <div class="btn-group pull-right">
            <button class="btn btn-danger" onclick="createZestBtn()" id="createZest"><i class="fa fa-file"></i> Create Zest Script !</button>
            <button class="btn btn-info" onclick="window.open(mySpace.zest_console_url);" id="ZestConsole"> <i class="fa fa-desktop"></i> Zest Script Console</button>
          </div>
       </div>

      </div>
    </div>
    <!-- Request & response search headers -->
    <div class="row-fluid">
      <div class="col-md-12">
        <form class="form-inline pull-right" role="form">
          <div class="form-group">
            <input type="text" class="form-control customTextSearch" col-id="7" placeholder="Search Requests">
          </div>
          <div class="form-group">
            <input type="text" class="form-control customTextSearch" col-id="8" placeholder="Search Response headers">
          </div>
          <div class="form-group">
            <input type="text" class="form-control customTextSearch" col-id="9" placeholder="Search Response bodies">
          </div>
        </form>
      </div>

    </div>

    <div class="container-fluid row-fluid">
      <div class="col-md-12">
         <table id="transactionLog" class="table table-striped table-bordered dt-responsive">
            <thead>
                <tr>
                    <th> Select </th>
                    <th> Link </th>
                    <th> Time </th>
                    <th> Duration </th>
                    <th class="textSearch"> Method </th>
                    <th class="textSearch"> Status </th>
                    <th class="textSearch"> URL </th>
                    <th> Raw Request </th>
                    <th> Response Headers </th>
                    <th> Response Body </th>
                </tr>
            </thead>
            <tbody>
            </tbody>
        </table>
      </div>
   </div>
  </div>
</div>

<!-- Transaction viewer modal -->
<div class="modal fade transaction-modal-lg" tabindex="-1" role="dialog" aria-labelledby="transactionLargeModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-lg">
    <div class="modal-content">
      <div class="modal-header">
        <div class="row-fluid">
          <div class="col-md-10">
            <p class="pull-left" id="transactionInfo"></p>
          </div>
          <div class="col-md-2">
            <div class="btn-group pull-right">
              <button type="button" class="btn btn-default" id="previousTransactionBtn" onclick="showPreviousTransaction();"><i class="fa fa-arrow-circle-left"></i></button>
              <button type="button" class="btn btn-default" id="nextTransactionBtn" onclick="showNextTransaction();"><i class="fa fa-arrow-circle-right"></i></button>
            </div>
          </div>
        </div>
      </div>

      <div class="modal-body">
        <!-- Nav tabs -->
        <ul class="nav nav-tabs" role="tablist">
          <li class="active"><a href="#raw_request_tab" role="tab" data-toggle="tab">Request</a></li>
          <li><a href="#raw_response_tab" role="tab" data-toggle="tab">Response</a></li>
        </ul>
        <br/>
        <!-- Tab panes -->
        <div class="tab-content">
          <div class="tab-pane active" id="raw_request_tab">
            <pre class="scrollablePre" id="raw_request_pre">Raw request</pre>
          </div>
          <div class="tab-pane" id="raw_response_tab">
            <pre class="scrollablePre" id="raw_response_headers_pre">Response Headers</pre>
            <br>
            <pre class="scrollablePre" id="raw_response_body_pre">Response Body</pre>
          </div>
        </div>
      </div>

    </div>
  </div>
</div>
<!-- End transaction viewer modal -->

<!--Fixed-footer for Zest creation-->
<div class="clear"></div>  <!--used for margin between body and footer-->
  <div class="navbar navbar-default navbar-fixed-bottom" id="#fixed_bar">
   <div class= container >
    <div style="text-align: center;">
      <button class="btn btn-primary btn-lg launch-modal" id="sendBtn" data-toggle="modal" data-target="#ScriptModal" disabled="true">Send
      </button>
      <button class="btn btn-danger btn-lg" onclick="closeFooter()">Close</button>
    </div>
  </div>
</div>

<!--Script Name Modal-->
<div class="modal fade" id="ScriptModal" tabindex="-1" role="dialog"
     aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog-center">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button"  class="close"  data-dismiss="modal" aria-hidden="true">&times;</button>
        <h4 class="modal-title" id="myModalLabel">Enter Script Name :</h4>
        <h6 class="modal-title" id="name_tip">(only alphanumeric characters)</h6>
      </div>
      <div class="modal-body">
        <p id="Filecheck" style="color:red"></p>
        <input type="text" id="textareaID" class="form-control"></input>
      </div>
      <div class="modal-footer">
         <button type="button" class="btn btn-primary" id="saveBtn" onclick="requestSender()">Generate!</button>
        <button type="button" class="btn btn-default"  data-dismiss="modal">Cancel</button>

      </div>
    </div>
  </div>
</div>

<script>

var mySpace = {
                    search_parameters: {},
                    transactions_api_url:"{{ transactions_api_url }}",
                    transactions_search_api_url:"{{ transactions_search_api_url }}",
                    transaction_log_url:"{{ transaction_log_url }}",
                    zest_console_url:"{{ zest_console_url }}"
                  };


var transactionLog;

var oTable;

//function to make checkboxes and footer visible
function createZestBtn(){
        disableInput("#createZest");
        fnShowHide(0);
        makeFooterVisible();
}


//function to toggle visibility of a column in datable
function fnShowHide(iCol){

        oTable = $('#transactionLog').dataTable();
        var bVis = oTable.fnSettings().aoColumns[iCol].bVisible;
        oTable.fnSetColumnVis( iCol, bVis ? false : true );
}

//handles close button events - 1)Hide column 2) disable footer 3) enable create zest script button
function closeFooter(){

        makeFooterInvisible();
        $('input:checkbox').removeAttr('checked');
        fnShowHide(0);
        enableInput("#createZest");
}

//functions to make footer visible/invisible
function makeFooterInvisible(){

        $('div[id="#fixed_bar"]').hide();
}

function makeFooterVisible(){

        $('div[id="#fixed_bar"]').show();
}

//enables send button only if at least one check box is ticked - event delegation
$(document).on('click','input:checkbox', function () {

        if ($('.check:checked').length) {
          enableInput("#sendBtn");
        }
        else{
          disableInput("#sendBtn");
        }
});

//clears text
function clearText(id){

        id='#'+id;
        $(id).val('');
}

// focuses/clears textbox in script modal window

$('#ScriptModal').on('show.bs.modal', function (e) {

        $('#textareaID').focus();
        clearText("textareaID");
        $("#Filecheck").text('');
});


//Checks filename, and send POST request with data (the new edited HTTP request)
function requestSender(){

        var file_name=$('#textareaID').val();
        //validates file name using regex
        if(validateFilename(file_name)){

          var trans=new Array();
          $.each(getSelectedTransaction(), function(index, obj){
          trans.push(obj.name);
          });

          var trans_str=JSON.stringify(trans);
          $.ajax({
            url:mySpace.transactions_api_url+"zest",
            type:'POST',
            data:{trans:trans_str,name:file_name},
            success:checkIfFileExists,
            traditional: true,
            error:function(xhr, textStatus, serverResponse){
                alertFail("Server replied: "+serverResponse);
                }
          });
        }
}

//gets selected transactions
function getSelectedTransaction(){

        var sData = $('input', oTable.fnGetNodes()).serializeArray();
        return(sData);
}

//Checks whether file exists else success
function checkIfFileExists(data, Status, xhr){

        if(data.exists!="true"){
           $('#ScriptModal').modal('hide');
           alertSuccess("Script Created :D");
        }
        else{
           $("#Filecheck").text("Script with this name already exists !");
        }

}

//checks for valid file_name
function validateFilename(elem){

        var alphaExp = /^[0-9a-zA-Z]+$/;
        if(elem.match(alphaExp)){
          return true;
        }
        else{
          $("#Filecheck").text("Script name invalid !");
        }
}

function showNextTransaction() {
  showTransactionWithOffset(mySpace.search_parameters["offset"]+1);
}

function showPreviousTransaction() {
  showTransactionWithOffset(mySpace.search_parameters["offset"]-1);
}

function openTransactionModal(offset) {
  $(".transaction-modal-lg").modal();
  showTransactionWithOffset(offset);
}

function showTransactionWithOffset(offset) {
  // First fetch the offset for id, then
  mySpace.search_parameters["limit"] = 1;
  mySpace.search_parameters["offset"] = offset;
  $.getJSON(mySpace.transactions_search_api_url+'?'+$.param(mySpace.search_parameters, true), function(response) {
    if (response["data"].length == 1) {
      // some variables
      var records_filtered = response["records_filtered"];
      var records_total = response["records_total"];
      var obj = response["data"][0];
      // Disable transaction buttons as neccessary
      enableInput("#previousTransactionBtn");
      enableInput("#nextTransactionBtn");
      if (offset == 0) {
        disableInput("#previousTransactionBtn");
      }
      if ((offset+1) == records_filtered) { // Remember offset is zero based
        disableInput("#nextTransactionBtn");
      }
      // First add the transaction info
      transactionInfo = '<div class="btn-group">';
      transactionInfo += '<button class="btn btn-primary btn-xs" onclick="window.open(\''+mySpace.transaction_log_url+obj.id+'\');">ID: '+obj.id+'</button>';
      transactionInfo += '<button class="btn btn-default btn-xs" disabled>TIME: '+obj.local_timestamp+'</button>';
      transactionInfo += '<button class="btn btn-default btn-xs" disabled>DURATION: '+obj.time_human+'</button>';
      transactionInfo += '<button class="btn btn-default btn-xs" disabled>'+(offset+1)+' of '+records_filtered+' (filtered from '+records_total+')</button>';
      transactionInfo += '</div>';
      $("#transactionInfo").html(transactionInfo);
      // Then add the raw request and highlight if any search terms
      $("#raw_request_pre").text(obj.raw_request);
      if (mySpace.search_parameters["raw_request"] !== undefined) {
        $("#raw_request_pre").highlight(mySpace.search_parameters["raw_request"]);
      }
      // Then add the response and highlight if any search terms
      $("#raw_response_headers_pre").text(obj.response_status+"\r\n"+obj.response_headers);
      var response_headers_highlight = [];
      if (mySpace.search_parameters["response_status"] !== undefined)
        response_headers_highlight.push(mySpace.search_parameters["response_status"]);
      if (mySpace.search_parameters["response_headers"] !== undefined)
        response_headers_highlight.push(mySpace.search_parameters["response_headers"]);
      $("#raw_response_headers_pre").highlight(response_headers_highlight);
      // Then the response body
      $("#raw_response_body_pre").text(obj.response_body);
      if (mySpace.search_parameters["response_body"] !== undefined) {
        $("#raw_response_body_pre").highlight(mySpace.search_parameters["response_body"]);
      }
      if (obj.binary_response){
          $("a[href='#raw_response_tab']").html("Response <span class='label label-default'>BASE64 Encoded</span>");
      } else {
          $("a[href='#raw_response_tab']").html("Response");
      }
    }
  });
}

function getArray(data, starting_offset) {
    var table_array = [];
    $.each(data, function(index, obj){
      var btns = '<div class="btn-group">';
      btns += '<button class="btn btn-default btn-xs" onclick="openTransactionModal('+(starting_offset+index)+');"><i class="fa fa-info-circle"></i></button>';
      btns += '<button class="btn btn-default btn-xs" onclick="window.open(\''+mySpace.transaction_log_url+obj.id+'\');"><i class="fa fa-desktop"></i></button>';
      btns += '</div>';
      // jQuery('#transactionLog').dataTable().fnAddData([
      table_array.push([
        '<input  type="checkbox"  class="check" name="'+obj.id+'"/>',
        btns,
        obj.local_timestamp,
        obj.time_human,
        obj.method,
        obj.response_status,
        obj.url,
        null,
        null,
        null
      ]);
    });
    return(table_array);
}

function dummyAjax(data, callback, settings) {
  // This function takes care of converting dataTable data into owtf api
  // and then the response back to dataTables type
  // Disabling all inputs when processing
  var get_parameters = {};
  var draw = data.draw;
  get_parameters['limit'] = data.length;
  get_parameters['offset'] = data.start;

  var columnMappings = {
    4: 'method',
    5: 'response_status',
    6: 'url',
    7: 'raw_request',
    8: 'response_headers',
    9: 'response_body'
  };

  // Iterate over mappings and add search parameters
  for (var k in columnMappings) {
    if (data.columns[k].search.value)
      get_parameters[columnMappings[k]] = data.columns[k].search.value;
  }

  mySpace.search_parameters = $.extend({}, get_parameters); // Make a copy of search parameters
  $.getJSON(mySpace.transactions_search_api_url+'?'+$.param(get_parameters, true), function (responseData) {
    enableInput('input'); // Reenable all inputs
    callback({
      "draw": draw,
      "recordsTotal": responseData["records_total"],
      "recordsFiltered": responseData["records_filtered"],
      "data": getArray(responseData["data"], data.start),
      "error": null
    });
  });
}

function drawTable() {
    $('#transactionLog').dataTable({
      "pagingType": "full_numbers",
      "iDisplayLength" : 100,
      "bAutoWidth": false,
      "bSort": false, // Not yet supported in API, can after shifting to postgres
      "bServerSide": true,
      "ajax": dummyAjax,
      "sDom": "ltip", // Remove global search & processing message
      "columnDefs": [{
        "targets": [7, 8, 9],
        "visible": false,
        "searchable": true,
      }],
    });

    var table = $("#transactionLog").DataTable();

    $('#transactionLog thead th.textSearch').each(function () {
        var title = $('#transactionLog thead th').eq( $(this).index() ).text();
        $(this).html('<input type="text" style="width: 100%; box-sizing: border-box;" class="form-control" placeholder="'+title+'"/>' );
    });

    // Apply search to custom boxes, but since these searches take type, only respond on
    // 'change' or 'return key press'
    $.each([0, 1, 2, 3, 4, 5], function ( colIdx ){
        $(':text', table.column( colIdx ).header() ).on('keyup change', function (e) {
          if (((e.type == "keyup") && (e.keyCode == 13)) || (e.type == "change")) {
            table
                .column( colIdx )
                .search( this.value )
                .draw();
          }
        });
    });

    // Apply search to custom boxes, but since these searches take type, only respond on
    // 'change' or 'return key press'
    $('.customTextSearch').each(function (index, obj){
      $(obj).on('keyup change', function(e){
        if (((e.type == "keyup") && (e.keyCode == 13)) || (e.type == "change")) {
          table
              .column(parseInt(this.getAttribute('col-id')))
              .search(this.value)
              .draw()
        }
      });
    });
}

$(document).ready(function() {
        drawTable();
        makeFooterInvisible();
        fnShowHide(0);
});
</script>
{% end %}
