var items = null;
var items_max_level = 0;
var padding_end_char = '0';
var padding_start_char = '0';
var padding_length = 8;

var useClone = true;

var itemFields = [];

var debug_item = -1;
function isDebugItem(item) {
  return (item.idlignes == debug_item);
}

function getItemFromElement(element)
{
    if (useClone) return (element?.clone ?? null);
    return element;
}
function AddCloneToElement(element)
{
  if (useClone) element.clone = Object.assign({}, element);
  return useClone;
}

function setLevelPadding(level)
{
  let retour = '';
  if (level > 0)
    for(i=0;i<level;i++) retour += '&nbsp;&nbsp;&nbsp;&nbsp;';
  return retour;
}

function itemGetParentItem(item) {
  return getItemFromElement(items.filter(ee => ee.idlignes == item.parent)[0]);
}

function setItems(data) {
  items = data;
  items_max_level = 0;

  // Ajouter une copie de lui-même à chaque item
  items.forEach(element => AddCloneToElement(element));

  // Trouver le niveau de l'item et mettre à jour le niveau max
  items.forEach(element => {
    let item = getItemFromElement(element);
    let parent = getItemFromElement(items.filter(ee => ee.idlignes == item.parent)[0]);

    if (isDebugItem(item)){
      myLog("ICI");
    }
    
    // gestion du rang vide
    if (item['rank'] == '') item['rank'] = '0';

    // Recherche du niveau, des ancêtres et des enfants
    item['level']=0;
    item['parents'] = [];
    while(parent != null){
      item['level'] += 1;
      item['parents'].push(parent['idlignes']);
      parent = getItemFromElement(items.filter(ee => ee.idlignes == parent.parent)[0]);
    }
    item['childs'] = [];
    items.forEach(ee => {if (ee['parent'] == item['idlignes']) item['childs'].push(ee['idlignes']) });

    if (items_max_level < item['level']) items_max_level = item['level']+1;

    item['debut'] = item['debut']?.padEnd(12,'0') ?? '000000000000';
    item['fin'] = item['fin']?.padEnd(12,'0') ?? '999999990000';

    if (item['debut']=='000000000000') item['debut']=item['fin'];

    item['visible'] = true;

    // En mode feuille, seules les feuilles sont visibles
    if (getParametreValeur(['mode_feuille']))
      if (item['childs'].length != 0)
        item['visible'] = false;

  });

  // Gestion de l'héritage des propriétés
  // On en profite pour calculer le chemin de l'item
  // Et pour calculer une valeur qui permette le tri dans l'affiche tree
  //   ie 
  let heritage = ['contrat','projet','intervenant','client'];
  for(i=0;i<items_max_level+1;i++) {
    items.forEach(element => {
      let item = getItemFromElement(element);
      if (item['level']==i) {
        let parent = getItemFromElement(items.filter(ee => ee.idlignes == item.parent)[0]);
        item['path'] = item['rank'].padStart(3,padding_start_char)+item['idlignes'].padStart(padding_length,padding_start_char);
        item['tritree']=item['path'];
        if (parent != null) {
          item['tritree']=parent['tritree']+item['debut']+item['tritree'];
          item['path'] = parent['path']+item['path'];
          for(var field in parent)
            if (heritage.indexOf(field) !== -1)
              if ((item[field] == null)||(item[field]==''))
                item[field] = parent[field];
        }
      }
    });
  }

  // Gestion de la remontée des propriétés
  for(i=items_max_level+1;i>=0;i--) {
    items.forEach(element => {
      let item = getItemFromElement(element);
      if (item['level']==i) {
        if (item.childs.length != 0) {
          item.jours_commandes = 0.0;
          item.jours_planifies = 0.0;
          item.jours_realises = 0.0;
          item.childs.forEach(child => {
            let childElement = items.filter(ee => ee.idlignes == child)[0];
            let enfant = getItemFromElement(childElement);
            if (isDebugItem(item)){
              myLog("ICI");
            }
            item.jours_commandes += customParseFloat(enfant.jours_commandes);
            item.jours_planifies += customParseFloat(enfant.jours_planifies);
            item.jours_realises += customParseFloat(enfant.jours_realises);
        });
        }
      }
      // L'element porte une commande, on annule le calcul
      if (customParseFloat(element.jours_commandes) > 0) item.jours_commandes = element.jours_commandes;
    });
  }
}

// -----------------------------------------------------------------------------
// ---- Cette fonction détermine la visibilité des item
// -----------------------------------------------------------------------------
function setItemsVisibility(){
  let mode_affichage=getContexteValeur('mode_affichage');
  let termine=getContexteValeur('termine');
  let client = getContexteValeur('client');
  let level = parseInt(getContexteValeur('level'));
  let idfiltre = stringDatePadDigits(parseInt(getContexteValeur('parent')),8);

  /*
   TODO : Faire la part des choses entre "contexte" et "filtre"
   A priori : 
      Un filtre dépend des données exemples 
          - filtrer parmi les clients
          - filtrer parmi les niveaux 
      Un contexte dépend de l'appli, exemples
          - utilistaeur connecté
          - mode d'affichage courant
  */
  client = getFiltreValeur('client');

  level = parseInt(getFiltreValeur('level'));
  if (idfiltre != '00000000'){
    let itemFiltre = getItemFromElement(items.filter(ee => ee.idlignes == parseInt(idfiltre))[0]);
    if (itemFiltre) level += itemFiltre['level'];
  }

  // Gestion de la visibilité individuelle
  // Que l'on va appeler 'filtre'
  items.forEach(element => {
    let item = getItemFromElement(element);

    if (isDebugItem(item)){
      myLog("ICI");
    }

    item['visible'] = true;
   
    // Contrôle du statut
    if ((item['status'] != 0)&&(item['status'] != 3)) item['visible'] = false;

    // Contrôle du client courant
    if ((client != '') && (client != item['client'])) item['visible'] = false;

    // Contrôle du niveau courant
    if (item['level'] > level) item['visible'] = false;

    // Cas particulier
    // ABS = Absences
    // FER = Fériés
    // REL = Releases de version
    // RDV = Rendez-Vous

    switch(mode_affichage){
      case 'absences':
        if (item['client'] != 'ABS') item['visible'] = false;
      break;
      case 'releases':
        if (item['client'] != 'REL') item['visible'] = false;
      break;
      case 'feries':
        if (item['client'] != 'FER') item['visible'] = false;
      break;
      case 'rdv':
        if (item['client'] != 'RDV') item['visible'] = false;
      break;
      case 'planning':
      case 'calendar_intervenants':
      case 'calendar_clients':

      break;      
      default:
        //if (item['client'] == 'ABS') item['visible'] = false;
        if (item['client'] == 'RDV') item['visible'] = false;
        if (item['client'] == 'FER') item['visible'] = false;
        if (item['client'] == 'REL') item['visible'] = false;
    }

    // Appliquer le filtre
    if ((idfiltre != '00000000') && (!item['path'].includes(idfiltre))) item['visible'] = false;

    if ((termine=='non')&&(item['status']!=0)) item['visible']=false;

    // La racine est toujours visible
    //  if (item['idlignes'] == 1) item['visible'] = true;
  });

  // Gestion des statuts hérités
  // Si un parent est terminé alors ses enfants aussi
  for(i=0; i<items_max_level+1;i++) {
    items.forEach(element => {
      let item = getItemFromElement(element);
      if (item['level']==i) {
        let parent = itemGetParentItem(item);
        if (parent != null) 
          if (parent['status'] != 0) {
            item['visible'] = false;
          }
      }
    });
  }    

  // Gestion de la visibilité héritée
  // Si un enfant est visible alors ses parents aussi
  for(i=items_max_level+1;i>=0;i--) {
    items.forEach(element => {
      let item = getItemFromElement(element);
      if (item['level']==i) {
        if (item['visible']) {
        let parent = itemGetParentItem(item);
        if (parent != null) 
            parent['visible'] = true;
        } 
      }
    });
  }
}

// -----------------------------------------------------------------------------
// ---- foncttons de tri des items
// -----------------------------------------------------------------------------
function sort2ItemsByField(item_a, item_b, field){
  let retour = 0;
  if (item_a[field] < item_b[field]) retour = -1;
  if (item_a[field] > item_b[field]) retour =  1;
  return retour;
}

function sort2ItemsByDates(item_a, item_b){
  let retour = 0;
  let maintenant = formatDatetoStringDateTime(new Date);

  // Par défaut, on trie par date de début
  let val_a = item_a['debut']?.padEnd(12,'0');
  let val_b = item_b['debut']?.padEnd(12,'0');

  // Sauf si l'item est en cours.
  if ((item_a.debut < maintenant)&&(item_a.fin>=maintenant))
    val_a = item_a['fin']?.padEnd(12,'0');

  if ((item_b.debut < maintenant)&&(item_b.fin>=maintenant))
    val_b = item_b['fin']?.padEnd(12,'0');

  // Ce qui n'est pas planifié est plus tard que le reste
  if (val_a == '') val_a = '999999999999';
  if (val_b == '') val_b = '999999999999';

  if (val_a < val_b) return -1;
  if (val_a > val_b) return  1;
  
  // retour = sort2ItemsByField(item_a, item_b, 'debut');
  // if (retour != 0) return retour;

  retour = sort2ItemsByField(item_a, item_b, 'rank');
  if (retour != 0) return retour;

  retour = sort2ItemsByField(item_a, item_b, 'idlignes');
  if (retour != 0) return retour;
  
  return retour;
}

function sort2ItemsByStartDates(item_a, item_b){
  retour = sort2ItemsByField(item_a, item_b, 'debut');
  if (retour != 0) return retour;

  retour = sort2ItemsByField(item_a, item_b, 'fin');
  if (retour != 0) return retour;

  retour = sort2ItemsByField(item_a, item_b, 'idlignes');
  if (retour != 0) return retour;

  return 0;
}

function sort2ItemsByEndDates(item_a, item_b){

  retour = sort2ItemsByField(item_a, item_b, 'fin');
  if (retour != 0) return retour;

  retour = sort2ItemsByField(item_a, item_b, 'debut');
  if (retour != 0) return retour;

  retour = sort2ItemsByField(item_a, item_b, 'idlignes');
  if (retour != 0) return retour;

  return 0;
}

function sortItemsByDate(){
  let maintenant = formatDatetoStringDateTime(new Date);

  items.sort((a, b) => {
    let item_a = getItemFromElement(a);
    let item_b = getItemFromElement(b);

    // Par défaut, on trie par date de début
    let val_a = item_a['debut'];
    let val_b = item_b['debut'];

    // Sauf si l'item est en cours.
    if ((item_a.debut < maintenant)&&(item_a.fin>=maintenant))
      val_a = item_a['fin'];

    if ((item_b.debut < maintenant)&&(item_b.fin>=maintenant))
      val_b = item_b['fin'];

    if (val_a < val_b) return -1;
    if (val_a > val_b) return  1;

    return sort2ItemsByStartDates(item_a, item_b);
  });
}

function sortItemsByEndDate() {
  items.sort((a, b) => {
    let item_a = getItemFromElement(a);
    let item_b = getItemFromElement(b);
    return sort2ItemsByEndDates(item_a, item_b);
  });
}

function sortItemsByStartDate() {
  items.sort((a, b) => {
    let item_a = getItemFromElement(a);
    let item_b = getItemFromElement(b);
    return sort2ItemsByStartDates(item_a, item_b);
  });
}

/* TO DELETE
function sortItemsByPath() {
  items.sort((a, b) => {
    let item_a = getItemFromElement(a);
    let item_b = getItemFromElement(b);
    return sort2ItemsByField(item_a, item_b, 'path');
  });
}
*/

function sortItemsByTriTreeValue() {
  items.sort((a, b) => {
    let item_a = getItemFromElement(a);
    let item_b = getItemFromElement(b);

    return sort2ItemsByField(item_a, item_b,'tritree');
  });
}

function sortItemsByPathDates() {
  items.sort((a, b) => {
    let item_a = getItemFromElement(a);
    let item_b = getItemFromElement(b);
    let retour = 0;

    // Les 2 items sont des feuilles du même parent
    // On les trie par rang puis par dates
    if ((item_a.childs.length == 0)&&(item_b.childs.length == 0)){
      if (item_a.parent === item_b.parent){
        retour = sort2ItemsByField(item_a, item_b,'rank');
        if (retour == 0) retour = sort2ItemsByDates(item_a, item_b);
      }
    }

    if (retour == 0) retour = sort2ItemsByField(item_a, item_b,'path');

    return retour;
  });
}

function sortItemsByClientParentDates() {
  return sortItemsByTriTreeValue();
}

/* TO DELETE
function sortItemsModeTasks() {
  sortItemsByPath();
}
*/

// -----------------------------------------------------------------------------
// ---- Cette fonction charge les items
// -----------------------------------------------------------------------------
function initDatagridItems() {
  datagridLoading();
  return getEntities(getContexteValeur('items_type'), __initDatagridItems);
}

function __initDatagridItems(data) {
  setItems(data);
  return afficherItems();
}

// -----------------------------------------------------------------------------
// ---- Placer un filtre
// -----------------------------------------------------------------------------
function filtrerItem(id){
  items.filter(item => item.idlignes == id).forEach(element => {
    let item=getItemFromElement(element);
    setContexteValeur('parent',id);
    setContexteValeur('client',item['client']);
    setContexteValeur('parent_level',item['level']);
  });
  gotoTop();
  afficherItems();
}

// -----------------------------------------------------------------------------
// ---- Cette fonction détermine l'entité à afficher en fonction du contexte
// -----------------------------------------------------------------------------
function clearElement(idElement){
  let element = document.querySelector(idElement);
  if (element) element.innerHTML = '';
}
function afficherItems() {
  let callback_affichage = datagrid_hooks[getContexteValeur('mode_affichage')];
  
  clearElement("#datagrid");
  clearElement("#calendrier");

  setItemsVisibility();
  
  if (callback_affichage === null) callback_affichage = datagrid_hooks['items'];
  
  callback_affichage();
  
  init_modal();
}

// -------------------------------------------------------------------------------------------------
// ---- Édition générique des items
// -------------------------------------------------------------------------------------------------
var items_edit_hooks = [];
var item_save_hooks = [];

function editerItem(id,libelle){
  let callback_edition=items_edit_hooks[getContexteValeur('type_courant')];

  items.filter(item => item.idlignes == id).forEach(resultat => {
    callback_edition = items_edit_hooks[resultat.type];
  });

  if ((callback_edition===null)||(callback_edition===undefined)) {
    callback_edition = items_edit_hooks['ITEM'];
  }

  return callback_edition(id, libelle);
}

function itemAPI(idlignes, bodyJSON) {
  let url = '../backend/api.php?entity=lignes';

  if (idlignes != 1) // On ne sauve pas la racine
  {
      if (idlignes != -1) url += '&id='+idlignes;

      fetch(url, {
          method: 'POST',
          body: bodyJSON, // string or object
          headers: {
              'Content-Type': 'application/json'
          }
      }).then((response) => response.json()).then((objet) => {
        initDatagridItems()
        .then(() => {
          if (idlignes != -1) itemInfo(idlignes); 
          else close_modal(); 
        });
      });
  }
}

function itemInfo(id){
  let cur_type='ITEM';
  items.filter(item => item.idlignes == id).forEach(resultat => {
    cur_type=resultat.type; 
  });
  return modal_hooks['ITEM']('type='+cur_type+':id='+id);
}

function itemSave(type, id){
  return item_save_hooks[type](id);
}

function itemChangeAttribut(id, attribut, valeur) {
  let bodyJSON = '{"idlignes":'+id+', "'+attribut+'": "'+valeur+'"}';
  return itemAPI(id, bodyJSON, itemInfo);
}

function eventItemChangeType(id, event) {
  return itemChangeAttribut(id, 'type',event.target.value);
}
function eventItemChangeStatus(id, event) {
  return itemChangeAttribut(id, 'status',event.target.value);
}

// -------------------------------------------------------------------------------------------------
// ---- Gestion générique des items
// -------------------------------------------------------------------------------------------------

itemFields['ITEM'] = ['parent','type','client','intervenant','libelle'];

let last_path='';
let last_path_retour;
function explodePath(path, id)
{
  let retour = '';
  let start = 0;
  const nb_numeros = 3;
  if (!last_path.includes(path)) last_path=path;

  if (last_path.length > nb_numeros*8) {
    start = (last_path.length - (nb_numeros*11));
    retour = '... > ';
  }

  for(let i=start;i<last_path.length;i+=11){
    let split = parseInt(last_path.substring(i,i+11));
    if (split != 1) {
      if (id == split) split = '<b>'+split+'</b>';
      if (i>start) retour += ' > ';
      retour += '<span onclick="itemInfo('+split+')" style="cursor: pointer">'+split+'</span>';
    }
    else retour = '...';
  }
  return retour ;
}

datagrid_hooks['items'] = function(){
  let element = document.querySelector("#datagrid");
  let contenu = "";

  sortItemsByTriTreeValue();

  contenu += '<table width="100vw">';
  contenu += " <thead>";
  contenu += "   <tr>";
  contenu += '    <th style="width:50px"><span class="nouveau" onclick="editerItem(-1,\'\')">Nouveau</span></th>';
  contenu += '    <th colspan="2">&nbsp;</th>';
  contenu += '    <th><span class="filtrer">Filtre</span></th>';
  contenu += "   </tr>";
  contenu += "   <tr>";
  contenu += '    <th style="width:50px">Client</th>';
  contenu += "    <th>Libelle</th>";
  contenu += "    <th><center>Type</center></th>";
  contenu += "    <th><center>État</center></th>";
  contenu += "   </tr>";
  contenu += "  </thead>";

  contenu += " <tbody>";
  items.forEach((element) => {
    let item = getItemFromElement(element);
    let texte = getNonNullTextValeur(item.libelle);

    if (item.status == 3) texte = "<strike>" + texte + "</strike>";

    // On n'affiche pas la racine
    if (item["idlignes"] == 1) return true;

    // On n'affiche que ce qui est marqué comme visible
    if (!item["visible"]) return true;

    contenu += '   <tr class="js-open-modal-trigger" data-modal-info="'+item.type+':id=' + item.idlignes + '">';
    contenu += '    <td style="width:50px">' + item.client + '</td>';
    contenu += "    <td>" + setLevelPadding(item["level"]) + texte + "</td>";
    contenu += '    <td><center>' + item.type + "</center></td>";
    contenu += "    <td><center>" + getStatusLibelleFromId(item.status) + "</center></td>";
    contenu += "   </tr>";
  });
  contenu += "  </body>";

  contenu += " <tfoot>";
  contenu += "   <tr>";
  contenu += '    <th colspan="4">&nbsp;</th>';
  contenu += "   </tr>";
  contenu += "  </foot>";
  contenu += "</table>";

  element.innerHTML = contenu;
}

function getItemDialogHeader(item){
  let retour='';
  let liste_select_types = ['TODO','TACHE','PRESTATION','ITEM'];

  retour += '<select onchange="eventItemChangeType('+item.idlignes+',event)">';
  liste_select_types.forEach((valeur)=>{
    let selected = '';
    if (valeur == item.type) selected='selected';
    retour += '<option value="'+valeur+'" '+selected+'>'+valeur+'</opton>';
  });
  retour += '</select><br>';       
  retour += ' n°'+explodePath(item.clone.path,item.idlignes);

  return retour;
}

modal_hooks['ITEM'] = function(parametres){
  let cur_type=null;
  let cur_id=null;
  let modal_header='';
  let modal_body='item inconnu !';
  let modal_footer='';    
  let paramSplit = parametres.split(':');

  paramSplit.forEach(element => {
    let elemSplit=element.split('=');
    if (elemSplit[0]==='type') cur_type=elemSplit[1];
    if (elemSplit[0]==='id') cur_id=elemSplit[1];
  });

  if (itemFields[cur_type]===undefined) cur_type='ITEM';

  items.filter(item => item.idlignes == cur_id).forEach(resultat => {
    let liste_status = ['Planifié', 'Supprimé', 'Annulé', 'Terminé','Reporté'];

    modal_header = getItemDialogHeader(resultat);

    modal_body  = '<table class="modal_table">';
    itemFields[cur_type].forEach(attribut => {
      let valeur = getNonNullTextValeur(resultat[attribut]);
      if (attribut =='libelle') valeur = '<b>'+valeur+'</b>';
      modal_body += '<tr class="tr1"><td>'+attribut+'</td><td>'+valeur+'</td></tr>';
    });
    modal_body += '</table>';

    modal_footer += '<div align="left" width="50%" style="float:left;padding-top:2vh">';
    modal_footer += '<button onclick="editerItem('+resultat.idlignes+',null)">Modifier</button>';
    modal_footer += '<button onclick="filtrerItem('+resultat.idlignes+')">Filtrer</button> ';
    modal_footer += '</div>';     
    
    modal_footer += '<div align="right" width="50%" style="float:right;padding-top:2vh">';
    modal_footer += '<button onclick="lancerPomodoroItem('+resultat.idlignes+')">Lancer</button>';    
    modal_footer += '<select onchange="eventItemChangeStatus('+resultat.idlignes+',event)">';
    liste_status.forEach((valeur,index)=>{
      let selected = '';
      if (index == resultat.status) selected='selected';
      modal_footer += '<option value="'+index+'" '+selected+'>'+valeur+'</option>';
    });
    modal_footer += '</select><br>';       

    modal_footer += '</div>';    
  });
      
  modal_footer += '<div style="clear:both">';

  modalSetHeader(modal_header);
  modalSetBody(modal_body);
  modalSetFooter(modal_footer);   
}

items_edit_hooks['ITEM'] = function (id, libelle) {
  let modal_header='';
  let modal_body='Item inconnu !';
  let modal_footer='<div align="right" width="100%" style="padding-top:2vh"><button onclick="itemSave('+id+')">Enregistrer</button></div>';

  let local_values = [];
  let local_placeholder = [];

  local_values['parent']=getContexteValeur('parent');
  local_values['type']=getContexteValeur('type_courant');
  local_values['client']=getContexteValeur('client');
  local_values['intervenant']=getContexteValeur('intervenant');
  local_values['libelle']=libelle;

  if (local_values['client']=='') local_values['client']=getTrigrammeCollaborateur(local_values['intervenant']);

  items.filter(item => item.idlignes == id).forEach(resultat => {
    local_values['type']=resultat['type'];
    itemFields[local_values['type']].forEach(attribut => {
      local_values[attribut]=resultat[attribut];
      local_placeholder[attribut]=resultat.clone[attribut];
    });
  });

  modal_header=local_values['type'];
  if (id != -1) modal_header+=' n°<b>'+id+'</b>';

  modal_body  = '<table class="modal_table"><form id="formulaire_lignes">';
  itemFields[local_values['type']].forEach(attribut => {
    modal_body += '<tr><td>'+attribut+'</td><td>'+getInputLabel(attribut,local_values[attribut], local_placeholder[attribut])+'</td></tr>';
  });
  modal_body += '</form></table>';

  modal_footer='<div align="left" width="100%" style="padding-top:2vh"><button onclick="itemSave(\''+local_values['type']+'\','+id+')">Enregistrer</button></div>';

  modalSetHeader(modal_header);
  modalSetBody(modal_body);
  modalSetFooter(modal_footer);   

  if (!modalDialog.open) modalDialog.showModal();
}
