{% extends "./template_wider.html" %}
{% block content %}
{% load static %}

    <script>
/**
 * @author Dimitry Kudrayvtsev
 * @version 2.1
 */

d3.gantt = function() {
    var FIT_TIME_DOMAIN_MODE = "fit";
    var FIXED_TIME_DOMAIN_MODE = "fixed";

    var margin = {
	top : 20,
	right : 40,
	bottom : 20,
	left : 150
    };
    var selector = 'body';
    var timeDomainStart = d3.timeDay.offset(new Date(),-3);
    var timeDomainEnd = d3.timeHour.offset(new Date(),+3);
    var timeDomainMode = FIT_TIME_DOMAIN_MODE;// fixed or fit
    var taskTypes = [];
    var taskStatus = [];
    var height = document.body.clientHeight - margin.top - margin.bottom-5;
    var width = document.body.clientWidth - margin.right - margin.left-5;

    var tickFormat = "%H:%M";

    var keyFunction = function(d) {
	return d.startDate + d.taskName + d.endDate;
    };

    var rectTransform = function(d) {
	return "translate(" + x(d.startDate) + "," + y(d.taskName) + ")";
    };

    var x = d3.scaleTime()
        .domain([ timeDomainStart, timeDomainEnd ])
        .range([ 0, width ])
        .clamp(true);

    //var y = d3.scaleOrdinal().domain(taskTypes).rangeRoundBands([ 0, height - margin.top - margin.bottom ], .1);
    var y = d3.scaleOrdinal()
        .domain(taskTypes)
        .range([ 0, height - margin.top - margin.bottom ], .1);

    /*
        var xAxis = d3.axisBottom()
        .scale(x);
    var yAxis = d3.axisLeft()
        .scale(y)
        .ticks(10);
        */
    //var xAxis = d3.svg.axis().scale(x).orient("bottom").tickFormat(d3.time.format(tickFormat)).tickSubdivide(true).tickSize(8).tickPadding(8);
    var xAxis = d3.axisBottom()
        .scale(x)
        .tickFormat(d3.timeFormat(tickFormat))
        .tickSize(8)
        .tickPadding(8);
    //.scale(x).tickFormat(d3.timeFormat(tickFormat)).tickSubdivide(true).tickSize(8).tickPadding(8);

    //var yAxis = d3.svg.axis().scale(y).orient("left").tickSize(0);
    var yAxis = d3.axisLeft().tickSize(0);

    var initTimeDomain = function(tasks) {
	if (timeDomainMode === FIT_TIME_DOMAIN_MODE) {
	    if (tasks === undefined || tasks.length < 1) {
		    timeDomainStart = d3.timeDay.offset(new Date(), -3);
		    timeDomainEnd = d3.timeHour.offset(new Date(), +3);
		    return;
	    }
	    tasks.sort(function(a, b) {
		    return a.endDate - b.endDate;
	    });
	    timeDomainEnd = tasks[tasks.length - 1].endDate;
	    tasks.sort(function(a, b) {
		    return a.startDate - b.startDate;
	    });
	    timeDomainStart = tasks[0].startDate;
	}
    };

    var initAxis = function() {
	x = d3.scaleTime().domain([ timeDomainStart, timeDomainEnd ]).range([ 0, width ]).clamp(true);
	y = d3.scaleBand().domain(taskTypes).range([ 0, height - margin.top - margin.bottom ], .1);
	//.rangeRoundBands([ 0, height - margin.top - margin.bottom ], .1);

    xAxis = d3.axisBottom().scale(x).tickFormat(d3.timeFormat(tickFormat))
        .tickSize(8)
        .tickPadding(8);
		//.tickSize(8).tickPadding(8);

	yAxis = d3.axisLeft().scale(y).tickSize(0);
    };

    function gantt(tasks) {

	initTimeDomain(tasks);
	initAxis();

	var svg = d3.select(selector)
	.append("svg")
	.attr("class", "chart")
	.attr("width", width + margin.left + margin.right)
	.attr("height", height + margin.top + margin.bottom)
	.append("g")
        .attr("class", "gantt-chart")
	.attr("width", width + margin.left + margin.right)
	.attr("height", height + margin.top + margin.bottom)
	.attr("transform", "translate(" + margin.left + ", " + margin.top + ")");

      svg.selectAll(".chart")
	 .data(tasks, keyFunction).enter()
	 .append("rect")
	 .attr("rx", 5)
         .attr("ry", 5)
	 .attr("class", function(d){
         return `bar bar-${d.status}`;
     })
	 .attr("y", 0)
	 .attr("transform", rectTransform)
	 .attr("height", function(d) { return y.bandwidth(); })
	 .attr("width", function(d) {
	     return Math.max(1,(x(d.endDate) - x(d.startDate)));
	     });


	 svg.append("g")
         .attr("class", "x axis")
         .attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")")
         .transition()
         .call(xAxis);

	 svg.append("g").attr("class", "y axis").transition().call(yAxis);

	 return gantt;

    };

    gantt.redraw = function(tasks) {

	initTimeDomain(tasks);
	initAxis();

        var svg = d3.select(".chart");

        var ganttChartGroup = svg.select(".gantt-chart");
        var rect = ganttChartGroup.selectAll("rect").data(tasks, keyFunction);

        rect.enter()
         .insert("rect",":first-child")
         .attr("rx", 5)
         .attr("ry", 5)
	 .attr("class", function(d){
	     if(taskStatus[d.status] == null){ return "bar";}
	     return taskStatus[d.status];
	     })
	 .transition()
	 .attr("y", 0)
	 .attr("transform", rectTransform)
	 .attr("height", function(d) { return y.bandwidth(); })
	 .attr("width", function(d) {
	     return Math.max(1,(x(d.endDate) - x(d.startDate)));
	     });

        rect.transition()
          .attr("transform", rectTransform)
	 .attr("height", function(d) { return y.bandwidth(); })
	 .attr("width", function(d) {
	     return Math.max(1,(x(d.endDate) - x(d.startDate)));
	     });

	rect.exit().remove();

	svg.select(".x").transition().call(xAxis);
	svg.select(".y").transition().call(yAxis);

	return gantt;
    };

    gantt.margin = function(value) {
	if (!arguments.length)
	    return margin;
	margin = value;
	return gantt;
    };

    gantt.timeDomain = function(value) {
	if (!arguments.length)
	    return [ timeDomainStart, timeDomainEnd ];
	timeDomainStart = +value[0], timeDomainEnd = +value[1];
	return gantt;
    };

    /**
     * @param {string}
     *                vale The value can be "fit" - the domain fits the data or
     *                "fixed" - fixed domain.
     */
    gantt.timeDomainMode = function(value) {
	if (!arguments.length)
	    return timeDomainMode;
        timeDomainMode = value;
        return gantt;

    };

    gantt.taskTypes = function(value) {
	if (!arguments.length)
	    return taskTypes;
	taskTypes = value;
	return gantt;
    };

    gantt.taskStatus = function(value) {
	if (!arguments.length)
	    return taskStatus;
	    taskStatus = value;
	return gantt;
    };

    gantt.width = function(value) {
	    if (!arguments.length)
	        return width;
        width = +value;
        return gantt;
    };

    gantt.height = function(value) {
        if (!arguments.length)
            return height;
        height = +value;
        return gantt;
    };

    gantt.tickFormat = function(value) {
        if (!arguments.length)
            return tickFormat;
        tickFormat = value;
        return gantt;
    };

    gantt.selector = function(value) {
	if (!arguments.length)
	    return selector;
	selector = value;
	return gantt;
    };

    return gantt;
};

    </script>
    <!--
    Due to a bug in d3_gnatt_chart - https://github.com/dk8996/Gantt-Chart/issues/27
    We have to utilise an older version of D3. This version of D3 is only used here in the timeline.
    Newer versions of D3 are utilised everywhere else
    -->


    <div class="card text-center">
        <div class="card-header">
            <h2>Timeline</h2>
        </div>
        <div class="card-body text-center">
            <form id="date_form">
                {% csrf_token %}
                <div class="form-row">
                    <!-- Start date -->
                    <div class="form-group col-md-4">
                        <label for="id_start_date">Start Date:</label>
                        {{ timeline_form.start_date }}
                    </div>

                    <!-- End date -->
                    <div class="form-group col-md-4">
                        <label for="id_end_date">End Date:</label>
                        {{ timeline_form.end_date }}
                    </div>

                    <!-- Objects -->
                    <div class="form-group col-md-4">
                        <label for="id_object_type">Object:</label>
                        {{ timeline_form.object_type }}
                    </div>
                </div>

                <div id="timeline" class="mt-4" style="width: 100%; overflow: auto;"></div>
            </form>
        </div>
    </div>



    <script>
        //Global varables
        var taskStatus = {
            "New" : "bar-new",
            "Open" : "bar-open",
            "Resolved" : "bar-resolved",
            "Closed" : "bar-closed"
        };

        /*
        Setup both the start_date and end_date fields with the
        datetime picker widget
         */
        $( "#id_start_date" ).datetimepicker({
            scrollInput: false,
            format: "Y-m-d",
            timepicker: false,
            maxDate: "{{ end_date|date:'Y-m-d' }}",
        });
        $( "#id_start_date" ).val("{{ start_date|date:'Y-m-d' }}");

        $("#id_end_date").datetimepicker({
            scrollInput: false,
            format: "Y-m-d",
            timepicker: false,
            minDate: "{{ start_date|date:'Y-m-d' }}",
        });
        $("#id_end_date").val("{{ end_date|date:'Y-m-d' }}");


        function render_gantt_chart() {
            /*
            The following function will render a gantt chart (timeline).

            Method
            ~~~~~~
            1.) Collect variables, like start and end date
            2.) Send - as POST - to collect the JSON of the data for gantt chart
            3.) Use the data from the JSON to construct the rest of the variables
            4.) Use those newly created variables to create the gantt chart using the D3_gantt_chart library
             */

            //Clear the board
            $("#timeline").html("");

            //Check dates
            if (!Date.parse($("#id_start_date").val()) || !Date.parse($("#id_end_date").val())) {
                alert("Sorry, but one of the dates is not a functional date and will cause issues!");
                return;
            }

            // 1.) Collect Variables
            var start_date = new Date(document.getElementById("id_start_date").value),
                end_date = new Date(document.getElementById("id_end_date").value),
                no_days = (end_date - start_date)/(1000*60*60*24),
                chart_width = 50 * no_days,
                objects = [],       //Could be project or task
                object_names = [],  //Project/tasks ID
                object_type = document.getElementById("id_object_type").value;


            $( "#id_start_date" ).datetimepicker({
                scrollInput: false,
                format: "Y-m-d",
                timepicker: false,
                maxDate: end_date,
            });

            $("#id_end_date").datetimepicker({
                scrollInput: false,
                format: "Y-m-d",
                timepicker: false,
                minDate: start_date,
            });


            // 2.) Send a POST to get JSON data
            $.ajax({
                url: '/timeline_data/',
                data: $("#date_form").serialize(),
                dataType: "JSON",
                type: "POST",
                success: function(data) {
                    //Obtained the JSON data
                    json_data = data;

                    // 3.) Construct more variables... who the fuck does not love variables
                    // A loop is used to navigate the JSON
                    for (var i=0; i<json_data.length;i++) {
                        if (object_type == "Project") {
                            var object_start_date = new Date(json_data[i]['fields']['project_start_date']),
                                object_end_date = new Date(json_data[i]['fields']['project_end_date']),
                                object_name = "PRO" + json_data[i]['pk'],
                                object_status = json_data[i]['fields']['project_status'];
                        } else if (object_type == "Task") {
                            var object_start_date = new Date(json_data[i]['fields']['task_start_date']),
                                object_end_date = new Date(json_data[i]['fields']['task_end_date']),
                                object_name = "TASK" + json_data[i]['pk'],
                                object_status = json_data[i]['fields']['task_status'];

                        } else if (object_type == "Quote") {
                            var object_start_date = new Date(json_data[i]['fields']['date_created']),
                                object_end_date = new Date(json_data[i]['fields']['quote_valid_till']),
                                object_name = "QUOTE" + json_data[i]['pk'],
                                object_status = json_data[i]['fields']['quote_stage_id'];
                        } else if (object_type == "Opportunity") {
                            var object_start_date = new Date(json_data[i]['fields']['date_created']),
                                object_end_date = new Date(json_data[i]['fields']['opportunity_expected_close_date']),
                                object_name = "OPPORTUNITY" + json_data[i]['pk'],
                                object_status = json_data[i]['fields']['opportunity_stage_id'];
                        }


                        //Shove that lovely data into the array
                        objects.push({
                            "startDate":object_start_date,
                            "endDate": object_end_date,
                            "taskName": object_name,
                            "status": object_status
                        });

                        object_names.push(object_name);
                    }

                    // 4.) Create that GANTT chart
                    var gantt = d3.gantt()
                        .taskTypes(object_names)
                        .taskStatus(taskStatus)
                        .tickFormat("%b %d, %Y")
                        .height(json_data.length * 50 + 25)
                        .width(chart_width)
                        .selector("#timeline")
                        .timeDomainMode("fixed")
                        .timeDomain([
                            start_date,
                            end_date
                        ]);


                    //gantt.redraw(objects);
                    gantt(objects);

                    // CONSOLE LOG EVERYTHING!!!
                    console.log(objects);
                    console.log(object_names);
                },
                error: function() {
                    new_error("Sorry, rendering the timeline is not possible at the moment due to errors.");
                    return false;
                }

            });
        }

        //Render the gantt chart
        render_gantt_chart();
    </script>

{% endblock %}

