
/**
 * QUERY SECTION
 * 
 *               */

// SPARQL Query text -- 'prefixes' and 'thisUrlParams' defined in people.js; 
let queryNetwork = prefixes + " SELECT COUNT(?event1) AS ?count1 COUNT(?event2) AS ?count2 ?uri2 SAMPLE(?label2) AS ?text \
WHERE { \
{?event1 rdf:type crm:EL1_Exchange_Letters . \
?event_to rdfs:subClassOf ?event1; \
rdf:type crm:EL2_Send_Letter ; \
crm:P01_has_domain ?pc_to . \
?pc_to crm:P02_has_range ?uri . \
?uri rdfs:label ?label . \
?event_from rdfs:subClassOf ?event1; \
rdf:type crm:EL3_Receive_Letter; \
crm:P01_has_domain ?pc_from . \
?pc_from crm:P02_has_range ?uri2 . \
?uri2 rdfs:label ?label2 . \
FILTER (?uri = <" + thisUrlParams.link + ">) \
} UNION { \
?event2 rdf:type crm:EL1_Exchange_Letters . \
?event_to rdfs:subClassOf ?event2; \
rdf:type crm:EL3_Receive_Letter ; \
crm:P01_has_domain ?pc_from . \
?pc_from crm:P02_has_range ?uri . \
?uri rdfs:label ?label . \
?event_from rdfs:subClassOf ?event2; \
rdf:type crm:EL2_Send_Letter; \
crm:P01_has_domain ?pc_to . \
?pc_to crm:P02_has_range ?uri2 . \
?uri2 rdfs:label ?label2 . \
FILTER (?uri = <" + thisUrlParams.link + ">) \
} \
}"

// 'prepareQueryURL' defined in people.js
let queryNet = prepareQueryURL(queryNetwork);

// do the query, call data processor on successful output
$.ajax({
    url: queryNet,
    dataType: "json",
    success: (data) => handle_word_network(data)
});



/**
 * COMPONENT CREATION SECTION
 * 
 *               */

// Master function, takes data output from the query and creates the HTML for the Word Cloud component of the page
function handle_word_network(json){
    // Pre-process data
    let tempArray = processQuery(json);
    let words = prepareWords(tempArray);
    // Create page elements
    doListPersonNetwork(tempArray);
    doWordCloud(words);
}


// Return structured object from raw query data for further processing
function processQuery(json) {
  
    const tempArray = [];
    
    $.each(
        json['results']['bindings'],
        (index, value) => {
          let text = value['text']['value'];
          let link = value['uri2']['value'];
          let sent = parseInt(value['count1']['value']);
          let received = parseInt(value['count2']['value']);
          let count = sent + received;
          tempArray.push({'text': text, 'sent': sent, 'received': received, 'count': count, 'hlink': link});
        }
    );

    tempArray.sort((a, b) => b.count - a.count);

    return tempArray;

}


// Define font size, according to the number of words and limiting the impact of huge counts -- to refactor??
function prepareWords(tempArray){

    const words = [];

    if (tempArray.length < 8) { // Less than 8 results -- font size is just = count/2 + constant
      for (let k=tempArray.length-1; k>=0; k--) {
        let text = tempArray[k]['text'];
        let preSize = tempArray[k]['count'] + 36;
        console.log('mann', preSize)
        let link = tempArray[k]['hlink'];
        words.push(
            {
                'text': text,
                'size': preSize/2 + 6,
                'hlink': link
            }
        );
      }
    } else { // More than 8 results -- font size = count except for especially "big" words
      let temp = 0;
      for (let k=tempArray.length-1; k>=0; k--) {
        let text = tempArray[k]['text']; 
        let count = tempArray[k]['count'];
        let link = tempArray[k]['hlink'];
        let preSize = 0;
        if ((count - temp) > 50) {
            preSize = temp + 12;
          } else {
            preSize = count;
        }
        words.push(
            {
                'text': text,
                'size': preSize/2 + 6,
                'hlink': link
            }
        );
        temp = preSize;
      }
    }

    console.log('tempArray', tempArray)
    console.log('words', words)
    
    return words;

}


// Create formatted list of people in the network
function doListPersonNetwork(tempArray){

    let ArrayNames = "";

    tempArray.forEach(element => {
        ArrayNames +=
        "<div class='item-place-person'>\
            <div class='item-place-person-label'>" +
                element['text'] +
                "<br /><span class='num_occ'>[Lettere inviate: " + element['sent'] + "]</span>\
                <br /><span class='num_occ'>[Lettere ricevute: " + element['received'] + "]</span>\
                <br /><span class='num_occ'>[Totale corrispondenza: " + element['count'] + "]</span>\
            </div>\
            <div class='item-place-person-action'>\
                <div class='persona' id='" + element['hlink'] +"'>\
                    <i class='fa fa-user' style='cursor:pointer'></i>\
                </div>\
            </div>\
        </div>";            
    });

    document.getElementById("list_person_network").innerHTML = ArrayNames;

}


// Create the word cloud
function doWordCloud(myWords){
    
    // Clear word cloud div
    $('#myWordCloud').empty();


    // OVERALL GRAPHIC SETTINGS for the cloud container -- id, dimensions, position

    // set the dimensions and margins of the graph
    let modifierWidth = 0.4;
    let modifierHeigth = 0.4;
    let marginHeight = 0;
    let marginWidth = 0;;

    let margin = {
        top: marginHeight,
        right: marginWidth,
        bottom: marginHeight,
        left: marginWidth};
    let width = modifierWidth*window.innerWidth;
    let height = modifierHeigth*window.innerHeight;
  
    // append the svg object to the body of the page
    let svg = d3.select("#myWordCloud")
        .append("svg")
        .attr("id", "wordcloudNetwork")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .attr("style", "border:1px solid black")
        .append("g")
        .attr("transform", "translate(" + (width*0.5) + "," + (height*0.5) + ")")
        .attr("overflow","scroll");

    // In case of empty cloud, draw special page and exit
    if (myWords.length == 0){
        drawEmptyWordCloud();
        return;
    }
    

    // THE ACTUAL CLOUD

    // Constructs a new cloud layout instance. It runs an algorithm to find the position of words that suits your requirements
    // Wordcloud features that are different from one word to the other must be here

    let layout = d3.layout.cloud() // Constructs the cloud
                          .size([1.5*width, 1.2*height]) // Sets width and height
                          .words(myWords) // put words in; expects an array of objects. Format is free, it all depends on the definition of the functions that are applied to define the cloud structure.
                          //
                          // A js curiosity: ~ is a bitwise not operator. On a number, the double bitwise not ~~ has the net effect of giving the integer part, that is: floor on positives and ceiling on negatives.
                          .rotate( () => { return ~~(Math.random() * 2);} )
                          .fontSize( word => { return word['size']; } ) // font size of words
                          .on("end", word => draw(word, svg));
    layout.start();
  
}


// Helper function for the Word Cloud --
// it draws the words
// Wordcloud features that are THE SAME from one word to the other can be here ??
function draw(words, svg) {
    let cloud = svg.selectAll("g text")
        .data(words, word => word.text) // What does this do?

        //Entering words
        cloud.enter()
             .append("text")
             .style("font-family", "Impact")
             .attr("text-anchor", "middle")
             .attr('font-size', 1)
             .append("a")
             .attr("href", word => word.hlink)
             .attr("data-toggle", "tooltip")
             .text( word => { return word.text; });

        //Entering and exiting words
        cloud.transition()
             .duration(600)
             .style("font-size", function(d) { return d.size + "px"; })
             .attr("transform", function(d) {
                    return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
             })
             .style("fill-opacity", 1);

        //Exiting words
        cloud.exit()
             .transition()
              .duration(200)
              .style('fill-opacity', 1e-6)
              .attr('font-size', 1)
              .remove();

}


// Helper function -- draw special empty word cloud if there are no occurrences
function drawEmptyWordCloud(){

    let wordIcon = "<div id='users_icon' class='no_info_icon'> \
    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'> \
      <!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d='M319.9 320c57.41 0 103.1-46.56 103.1-104c0-57.44-46.54-104-103.1-104c-57.41 0-103.1 46.56-103.1 104C215.9 273.4 262.5 320 319.9 320zM369.9 352H270.1C191.6 352 128 411.7 128 485.3C128 500.1 140.7 512 156.4 512h327.2C499.3 512 512 500.1 512 485.3C512 411.7 448.4 352 369.9 352zM512 160c44.18 0 80-35.82 80-80S556.2 0 512 0c-44.18 0-80 35.82-80 80S467.8 160 512 160zM183.9 216c0-5.449 .9824-10.63 1.609-15.91C174.6 194.1 162.6 192 149.9 192H88.08C39.44 192 0 233.8 0 285.3C0 295.6 7.887 304 17.62 304h199.5C196.7 280.2 183.9 249.7 183.9 216zM128 160c44.18 0 80-35.82 80-80S172.2 0 128 0C83.82 0 48 35.82 48 80S83.82 160 128 160zM551.9 192h-61.84c-12.8 0-24.88 3.037-35.86 8.24C454.8 205.5 455.8 210.6 455.8 216c0 33.71-12.78 64.21-33.16 88h199.7C632.1 304 640 295.6 640 285.3C640 233.8 600.6 192 551.9 192z'/> \
    </svg> \
    <p>Nessuna persona trovata</p> \
    </div>";

    $("#wordcloudNetwork").css("display", "none");
    $("#references_network").css("display", "none");

    document.getElementById("myWordCloud").innerHTML = wordIcon;

}



// Customized word cloud code

// Takes a list of words, returns the innerHTML for a Word Cloud as a string containing multiple <g> svg elements
function createWordCloud(words){

    const rectObjs = []
    let allBooms = 0
    let attempts = 0;
    for(let ind=0;ind<words.length;ind++){

        let id0 = "word"+ind;
        let praaaa = document.getElementById(id0).getBoundingClientRect();
        //console.log('BB of '+id0, praaaa);

        attempts++;
        let boom = false;
        // rectangle definition
//        let width = 120 + Math.round(50*Math.random());
//        let height = 40;
        let fontSize = getFontSize(ind);
        let width = praaaa.width;
        //let height = fontSize;
        let height = praaaa.height;
        let xR = 1250 + Math.round( (Math.random()-0.5)*(1000 + 6*ind) );
        let yR = 750 + Math.round( (Math.random()-0.5)*(400 + 4*ind) );
        let angle = 90*(Math.floor(3*Math.random())-1);
        let text = words[ind];
        //console.log('Rect:', width, height, xR, yR, angle, text);
        let newRect = new Rect(width, height, xR, yR, angle, text, fontSize);
        //console.log('nnn', newRect);
        for(let rect of rectObjs){
            boom = checkColl(newRect, rect);
            if(boom) break;
        }
        if(boom){
            allBooms++;
            if(allBooms<10) ind--;
            else(allBooms = 0);
            continue;
        }
        allBooms = 0;
        rectObjs.push(newRect);
    }
    console.log('Attempted:', attempts);
    console.log('Placed:', rectObjs.length);

    const rectTexts = [];
    rectObjs.forEach(rect => rectTexts.push(rect.printCoords()));
    let rects = rectTexts.join('\n');

    return rects;
}

function getFontSize(weight){
    return Math.max(80-weight, 30);
}
