text:  /* The smooth Class Library
    * Copyright (C) 1998-2021 Robert Kausch <robert.kausch@gmx.net>
    *
    * This library is free software; you can redistribute it and/or
    * modify it under the terms of "The Artistic License, Version 2.0".
    *
    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
    * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
    * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
  
  #include "section.h"
  #include "stringitem.h"
  
  Signal1<Void, ListEntry *>	 Section::onSelectItem;
  
  Section::Section()
  {
  	list = NIL;
  }
  
  Section::~Section()
  {
  	foreach (StringItem *item, items) delete item;
  	foreach (Tree *tree, trees) delete tree;
  
  	foreach (Section *section, sections) delete section;
  }
  
  Bool Section::Parse(XML::Node *section, List *plist, Array<ListEntry *> &entries)
  {
  	if (section == NIL) return False;
  
  	list = plist;
  
  	if (section->GetAttributeByName("name") != NIL) name = section->GetAttributeByName("name")->GetContent();
  
  	for (Int i = 0; i < section->GetNOfNodes(); i++)
  	{
  		XML::Node	*entry = section->GetNthNode(i);
  
  		if (entry->GetName() == "entry")
  		{
  			GUI::Font	 blackFont;
  			GUI::Font	 redFont;
  			GUI::Font	 orangeFont;
  
  			blackFont.SetColor(Setup::ClientTextColor);
  			redFont.SetColor(Color(255, 0, 0));
  			orangeFont.SetColor(Color(255, 127, 36));
  
  			if (entries.Get(entry->GetAttributeByName("id")->GetContent().ToInt()) != NIL)
  			{
  				StringItem	*item = (StringItem *) entries.Get(entry->GetAttributeByName("id")->GetContent().ToInt());
  
  				item->SetTranslation(entry->GetContent());
  
  				if	(item->GetTranslation() == NIL)						   item->SetFont(redFont);
  				else if (item->GetOriginal() != entry->GetAttributeByName("string")->GetContent()) item->SetFont(orangeFont);
  				else										   item->SetFont(blackFont);
  			}
  			else
  			{
  				StringItem	*item = new StringItem(entry->GetAttributeByName("id")->GetContent().ToInt(),
  								       entry->GetAttributeByName("string")->GetContent(),
  								       entry->GetContent());
  
  				if (item->GetTranslation() == NIL) item->SetFont(redFont);
  				else				   item->SetFont(orangeFont);
  
  				list->Add(item);
  
  				entries.Add(item, item->GetID());
  
  				items.Add(item, item->GetID());
  			}
  		}
  		else if (entry->GetName() == "section")
  		{
  			if (sections.Get(entry->GetAttributeByName("name")->GetContent().ComputeCRC32()) == NIL)
  			{
  				Section	*section = new Section();
  				Tree	*tree	 = new Tree(entry->GetAttributeByName("name")->GetContent());
  
  				section->Parse(entry, tree->GetList(), entries);
  
  				tree->Open();
  				list->Add(tree);
  
  				sections.Add(section, section->GetName().ComputeCRC32());
  
  				trees.Add(tree);
  			}
  			else
  			{
  				Section	*section = sections.Get(entry->GetAttributeByName("name")->GetContent().ComputeCRC32());
  
  				section->Parse(entry, section->list, entries);
  			}
  		}
  	}
  
  	/* OnSelectEntry may already be connected if we parsed a template
  	 * before, so try to disconnect before actually connecting it.
  	 */
  	list->onSelectEntry.Disconnect(&Section::OnSelectEntry, this);
  	list->onSelectEntry.Connect(&Section::OnSelectEntry, this);
  
  	return True;
  }
  
  Bool Section::Save(XML::Node *xmlSection, const String &templateName)
  {
  	for (Int i = 0; i < items.Length(); i++)
  	{
  		StringItem	*item = items.GetNth(i);
  
  		/* If we have a template, save only
  		 * entries with a translation.
  		 */
  		if (templateName == NIL || item->GetTranslation() != NIL)
  		{
  			XML::Node	*node = xmlSection->AddNode("entry", item->GetTranslation());
  
  			node->SetAttribute("id", String::FromInt(item->GetID()));
  			node->SetAttribute("string", item->GetOriginal());
  		}
  	}
  
  	foreach (Section *section, sections)
  	{
  		XML::Node	*node = xmlSection->AddNode("section");
  
  		node->SetAttribute("name", section->GetName());
  
  		section->Save(node, templateName);
  	}
  
  	return True;
  }
  
  Bool Section::Export(IO::OutStream &stream, Int level)
  {
  	String	 indent;
  
  	indent.FillN(' ', level * 2);
  
  	for (Int i = 0; i < items.Length(); i++)
  	{
  		StringItem	*item = items.GetNth(i);
  
  		/* Save only entries with a translation.
  		 */
  		if (item->GetTranslation() != NIL) stream.OutputLine(String(indent).Append(item->GetTranslation().Replace("\n", " \\ ")));
  	}
  
  	foreach (Section *section, sections)
  	{
  		if (section->items.Length() == 0 && section->sections.Length() == 0) continue;
  
  		stream.OutputString("\n");
  		stream.OutputLine(String(indent).Append("# ").Append(section->GetName()));
  		stream.OutputString("\n");
  
  		section->Export(stream, level + 1);
  	}
  
  	return True;
  }
  
  Bool Section::Filter(const String &string, List *list_filtered)
  {
  	if (list == NIL) return True;
  
  	for (Int i = 0; i < list->Length(); i++)
  	{
  		const ListEntry	*entry = list->GetNthEntry(i);
  
  		if (entry->GetObjectType() == Tree::classID)
  		{
  			Tree	*tree	 = new Tree(entry->GetText());
  
  			sections.Get(entry->GetText().ComputeCRC32())->Filter(string, tree->GetList());
  
  			if (tree->Length() > 0)
  			{
  				tree->Open();
  				list_filtered->Add(tree);
  			}
  			else
  			{
  				delete tree;
  			}
  		}
  		else if (entry->GetObjectType() == StringItem::classID && entry->GetText().ToLower().Contains(string))
  		{
  			StringItem	*item = new StringItem(((StringItem *) entry)->GetID(),
  							       ((StringItem *) entry)->GetOriginal(),
  							       ((StringItem *) entry)->GetTranslation());
  
  			item->SetFont(entry->GetFont());
  
  			list_filtered->Add(item);
  		}
  	}
  
  	/* OnSelectEntry may already be connected if we parsed a template
  	 * before, so try to disconnect before actually connecting it.
  	 */
  	list_filtered->onSelectEntry.Disconnect(&Section::OnSelectEntry, this);
  	list_filtered->onSelectEntry.Connect(&Section::OnSelectEntry, this);
  
  	return True;
  }
  
  Void Section::OnSelectEntry(ListEntry *entry)
  {
  	onSelectItem.Emit(entry);
  }
  