/***************************************************************************

    source::worx xtree
    Copyright © 2024-2025 c.holzheuer
    christoph.holzheuer@gmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


#include <xqsectionmanager.h>


//! kontstruktor. übergibt den start-index und einen model-knoten mit der beschreibung
//! der datenknoten.

XQModelSection::XQModelSection(const QModelIndex& modelIndex, XQNodePtr sheetNode)
  : _modelIndex{ modelIndex }, _sectionSheetRootNode{ sheetNode }
{

}


//! elementvergleich.

bool XQModelSection::operator==(const XQModelSection& other) const
{
  return _modelIndex == other._modelIndex && _sectionSheetRootNode == other._sectionSheetRootNode;
}


//! true wenn der start-index valide und ein model-knoten vorhanden.

bool XQModelSection::isValid() const
{
  return _modelIndex.isValid() && _sectionSheetRootNode;
}

QModelIndex XQModelSection::startIndex() const
{
  return _modelIndex.operator QModelIndex();
}

XQNodePtr XQModelSection::sectionRootNode() const
{
  return _sectionSheetRootNode;
}

//! Gibt den sheet-node zurück, das ist die model-beschreibung,
//! siehe modelsheet.xml:
//! <section>
//!   <header>
//!   <data> <- dort

//! __fix! das versteht doch kein mensch!

XQNodePtr XQModelSection::sheetRootNode() const
{
  return _sectionSheetRootNode->child( c_ModelSheet );
}


//! Gibt den content root node zurück, das ist der
//! zeiger auf die realen inhalte.

XQNodePtr XQModelSection::contentRootNode() const
{
  return _contentRootNode;
}

void XQModelSection::setContentRootNode( const XQNodePtr contentRootNode ) const
{
  _contentRootNode = contentRootNode;
}


//! gibt die zeile des start-index zurück.

int XQModelSection::XQModelSection::firstRow() const
{
  return _modelIndex.row();
}


//! gibt den 'content type' zurück.

const QString& XQModelSection::contentType() const
{
  //qDebug() << " ---AUA & AUS!";
  return _sectionSheetRootNode->attribute( c_ContentType );
}


//! gibt das dieser section entsprechende header-item zurück.

XQItem& XQModelSection::XQModelSection::headerItem() const
{
  return XQItem::xqItemFromIndex( _modelIndex );
}


//! testet, ob die unter 'sectionKey' eine gültige section vorhanden ist.

bool XQSectionManager::hasValidSection(const QString& sectionKey) const
{
  if (!_sections.contains(sectionKey) )
    return false;
  return _sections.at(sectionKey).isValid();
}

const XQModelSection& XQSectionManager::sectionByKey( const QString& sectionKey ) const
{
  if( hasValidSection( sectionKey ) )
    return _sections.at(sectionKey);

  throw XQException( "No section for key", sectionKey);

}


//! gibt für eine zeile die 'zuständige' section zurück: der bestand an section wird
//! nach der passenden section durchsucht.

const XQModelSection& XQSectionManager::sectionByRow(int itemRow ) const
{


  for (const auto& section : _sections)
  {
    qDebug() << " ---- SEC: " << itemRow  << " -> " <<  section.firstRow() << " :  " << lastRow( section );
    XQSectionRange range = sectionRange(section);
    if( itemRow >= range.firstRow && itemRow <= range.lastRow)
      return section;
  }

  throw XQException( "No section for item row", QString::number(itemRow));

}


const XQModelSection& XQSectionManager::createSection(const QModelIndex& modelIndex, XQNodePtr sheetNode)
{
  const QString& sectionKey = sheetNode->attribute(c_ContentType);
  //qDebug() << " --- create Section: " << sectionKey << ": " << modelIndex.data().toString();
  XQModelSection section(modelIndex, sheetNode );
  _sections.addAtKey( sectionKey, section);
  return sectionByKey(sectionKey);
}


//! ermittelt die zeile unterhalb des gegebenen modelindex,
//! zum einfügen neuer items ebendort.

int XQSectionManager::lastRow(const XQModelSection& section ) const
{
  //qDebug() << " -- last row in section: " << section.startIndex().data().toString() << " --> " << section.startIndex().row();
  // row() der section unterhalb dieser
  // __fix? index mit speichern?
  int index = _sections.indexOf(section);
  if (index > -1)
  {
    // last section? return last row of model
    if (index == _sections.size() - 1)
      return section.startIndex().model()->rowCount() - 1;
    // return row above the row of the next section -> last row of given section
    return _sections.at(index+1).firstRow() - 1;
  }
  return -1;
}


XQSectionRange XQSectionManager::sectionRange(const XQModelSection& section ) const
{
  return XQSectionRange{ section.startIndex().row(), lastRow(section) };
}


//! gibt alle sections aus, zum ankucken.

void XQSectionManager::dump() const
{
  qDebug() << " --- sections dump(): " <<_sections.size() << " entries.";
  for( int i = 0; i<_sections.size(); ++i )
  {
    QModelIndex idx = _sections.at(i).startIndex();
    qDebug() << " --- sections:" << i << "row: " << idx.row() << " keyOf(i): " << _sections.keyOf(i) << " indexData: "<< idx.data().toString() << " itemData: " << XQItem::xqItemFromIndex(idx).data(Qt::DisplayRole).toString();
  }

}














