/// DicomTree.cpp
/**
*/

#if defined(__WXGTK__) || defined(__WXMOTIF__)
  #include <wx/wx.h>
#endif

#include <wx/wxprec.h>
#include <wx/treectrl.h>

#include "SeriesHandler.h"
#include "StringConvert.h"
#include "DicomTree.h"

using namespace jcs;

///
/**
*/
DicomTreeCtrl::DicomTreeCtrl(wxWindow* parent, wxWindowID id, long more_styles)
: jcsTreeCtrl(parent, id, wxTR_HIDE_ROOT | wxTR_HAS_BUTTONS | 
       wxTR_LINES_AT_ROOT  | wxSUNKEN_BORDER | more_styles, "Dicom series")
{
}


///
/**
*/
DicomTreeCtrl::DicomTreeCtrl(wxWindow* parent, wxWindowID id) 
: jcsTreeCtrl(parent, id, wxTR_HIDE_ROOT | wxTR_HAS_BUTTONS | 
       wxTR_LINES_AT_ROOT  | wxSUNKEN_BORDER, "Dicom series")
{
}


///
/** Adds a series. Heirarchy is Subject->Study->Series->File.
    In many cases, DICOM is encoded with Unicode. File systems
    typically use UTF-8. The wxStuff also uses UTF-8, so 
    conversion from Unicode to UTF-8 is needed where the input 
    data is Unicode-encoded. This is the reason for the various
    invocations of From8BitData below.
    \param series A pointer to the SeriesHandler for the data
                  to be added.
*/
void
DicomTreeCtrl::AddSeries(SeriesHandler* series)
{
  // Processing for subject level of the heirarchy.
  std::string subject;
  if (!series->Find("PatientName", subject)) {
    subject = "no name";
  }

  //std::cout << subject << std::endl;
  
  wxTreeItemId subjectTreeId;
  if (!mTreeMap.count(subject)) {
  
    //std::string itemText("Subject name: ");
    wxString itemText(_("Subject name: "));
    itemText += wxString::From8BitData(subject.c_str()).wc_str();
    //itemText += wxString(wxString::From8BitData(subject.c_str()).wc_str(), wxConvLocal);
    //std::cout << itemText << std::endl;
    //itemText.append(subject);
    subjectTreeId = AppendItem(
      GetRootItem(),
      itemText,
      folder_icon, -1,
      new jcsTreeItemData(subject, dtSUBJECT)
    );

    SetItemImage(
      subjectTreeId, 
      open_folder_icon,
      wxTreeItemIcon_Expanded
    );

    mTreeMap[subject] = subjectTreeId;
  }
  else {
    subjectTreeId = mTreeMap[subject];
  }

  // Processing for the study level of the heirarchy.
  std::string study_uid;
  //if (!series->Find("StudyInstanceUid", study_uid)) {
  if (!series->Find("StudyInstanceUID", study_uid)) {
    study_uid = "no study id";
  }

  wxTreeItemId studyTreeId;
  if (!mTreeMap.count(study_uid)) {

    std::string number;
    //series->Find("StudyId", number);
    series->Find("StudyID", number);
    std::string desc;
    series->Find("StudyDescription", desc);
    std::string date;
    series->Find("StudyDate", date);

    wxString itemText(_("Study "));  // Use this form to compile with wxWidgets < 3.0.0
    itemText += wxString(number.c_str(), *wxConvCurrent);  // Use this form to compile with wxWidgets < 3.0.0
    itemText += wxString(_("     "));
    itemText += wxString(date.c_str(), *wxConvCurrent);
    itemText += wxString(_("     "));
    itemText += wxString(desc.c_str(), *wxConvCurrent);
    /**
    wxString itemText("Study ");
    itemText += wxString(number);
    itemText += wxString("     ");
    itemText += wxString(date);
    itemText += wxString("     ");
    itemText += wxString(desc);
    **/
    /**
    std::string itemText("Study ");
    itemText.append(number);
    itemText.append("     ");
    itemText.append(date);
    itemText.append("     ");
    itemText.append(desc);
    **/

    studyTreeId = AppendItem(
      subjectTreeId,
      itemText,
      folder_icon, -1, 
      new jcsTreeItemData(study_uid, dtSTUDY)
    );
    SetItemImage(
      studyTreeId, 
      open_folder_icon,
      wxTreeItemIcon_Expanded
    );

    mTreeMap[study_uid] = studyTreeId;
  }
  else {
    studyTreeId = mTreeMap[study_uid];
  }

  // Processing for the series level of the heirarchy.
  std::string series_uid = series->GetSeriesUid();

  wxTreeItemId seriesTreeId;

  if (!mTreeMap.count(series_uid)) {

    std::string number;
    if (!series->Find("SeriesNumber", number)) {
      number = "0";
    }
    number = jcs::itos(jcs::stoi(number));
    std::string protocol;
    series->Find("ProtocolName", protocol);
    std::string desc;
    series->Find("SeriesDescription", desc);
    std::string date;
    series->Find("SeriesDate", date);

    std::string itemText("Series ");
    itemText.append(number);
    itemText.append("     ");
    itemText.append(date);
    itemText.append("     ");
    itemText.append(protocol);
    if (protocol != desc) {
      itemText.append(" ");
      itemText.append(desc);
    }

    seriesTreeId = AppendItem(
      studyTreeId, 
      wxString(wxString::From8BitData(itemText.c_str()).wc_str(), wxConvLocal),
      folder_icon, -1, 
      new jcsTreeItemData(series_uid, dtSERIES)
    );
    SetItemImage(
      seriesTreeId, 
      open_folder_icon,
      wxTreeItemIcon_Expanded
    );

    mTreeMap[series_uid] = seriesTreeId;
  }
  else {
    seriesTreeId = mTreeMap[series_uid];
  }

  CollapseAndReset(seriesTreeId);
  
  // Processing for each file in a series.
  // File names and paths are typically encoded with UTF-8, so
  // no From8BitData processing is needed here.
  std::vector<std::string> names = series->GetFilenames();
  std::vector<std::string>::iterator it = names.begin();
  while (it != names.end()) {
    AppendItem(
      seriesTreeId,
      wxString(it->c_str(), wxConvLocal),
      file_icon, -1,
      new jcsTreeItemData(*it, dtFILE)
    );
    ++it;
  }
}


///
/**
*/
std::vector<std::string>
DicomTreeCtrl::GetChildSeries(wxTreeItemId branch)
{
  std::vector<std::string> v;

  jcsTreeItemData* item = (jcsTreeItemData*) GetItemData(branch);

  switch (item->GetItemType()) {

  case dtSERIES :

    v.push_back(item->GetUid());
    break;

  case dtSTUDY : 
  case dtSUBJECT : 
    
    if (ItemHasChildren(branch)) {
      int n_children = GetChildrenCount(branch, false);
      wxTreeItemIdValue cookie;
      wxTreeItemId child = GetFirstChild(branch, cookie);
      std::vector<std::string> v2 = GetChildSeries(child);
      v.insert(v.end(), v2.begin(), v2.end());

      for (int i = 1; i < n_children; ++i) {
        child = GetNextChild(branch, cookie);
        v2 = GetChildSeries(child);
        v.insert(v.end(), v2.begin(), v2.end());
      }
    }
    break;

  default : 
    break;
  }

  return v;
}


///
/**
*/
std::vector<std::string>
DicomTreeCtrl::GetFilenames()
{
  std::vector<std::string> filenames;

  jcsTreeMap::iterator it = mTreeMap.begin();
  jcsTreeMap::iterator end = mTreeMap.end();

  while (it != end) {
    wxTreeItemId item = (*it).second;
    if (GetItemType(item) == dtFILE) {
      filenames.push_back(static_cast<const char*>(GetItemText(item).mb_str(wxConvLocal)));
    }
    ++it;
  }
  return filenames;
}


///
/**
*/
std::vector<wxString> 
DicomTreeCtrl::GetFilesInSeries(const wxTreeItemId item)
{
  std::vector<wxString> files;
  wxTreeItemId local_item = item;
  if (GetItemType(local_item) == dtFILE) {
    wxTreeItemId parent = GetItemParent(local_item);
    wxTreeItemIdValue cookie;
    local_item = GetFirstChild(parent, cookie);
    while (local_item.IsOk()) {
      files.push_back(GetItemText(local_item));
      local_item = GetNextChild(parent, cookie);
    }
  }
  return files;
}
