/* -*- indent-tabs-mode: nil; -*-
 *
 * This file is part of the Mango recipe management distribution.
 * Copyright (c) 2000-2003, Roland Jesse
 * All rights reserved.
 *
 * For license and copyright information see the file COPYRIGHT or 
 * <http://www.opensource.org/licenses/bsd-license.html>.
 *
 * $Id: RKExporter.cpp,v 1.8 2003/05/11 16:13:06 rjesse Exp $
 */

#include "RKExporter.h"
#include "RecipeModel.h"
#include "resources.h"
#include <qfile.h>
#include <qregexp.h>

RKExporter::RKExporter( RecipeModel* rm)
   : Exporter(rm)
{
}

RKExporter::RKExporter( const Recipe& r)
   : Exporter(r)
{
}

QString
RKExporter::getExtensions()
{
   QString ret( tr( "Rezkonv recipes"));
   ret += "(*.rk)";
   return ret;
}

void
RKExporter::apply()
   throw (Error)
{
   if (m_fname.isEmpty()) throw( Error( tr( "RKExporter: no file name set.")));

   try {
      buildStringList();
   }
   catch (Error& e) {
      throw( e);
   }
   QString fullString = m_lines.join( "\n");
   QFile f( m_fname);
   if (!f.open( IO_WriteOnly)) {
      QString msg( tr( "Could not open file %1 for writing.") .arg( m_fname));
      throw Error( msg);
   }
   QTextStream ts( &f);
   ts << fullString << flush;
   f.close();
} // apply()

/*!
  Fill up the internal string list (m_lines).

  One string for each line of output is created.
*/
void
RKExporter::buildStringList()
   throw( Error)
{
   if (m_type == RECIPE) convertRecipe();
   else if (m_type == COOKBOOK) convertCookbook();
   else throw( Error( tr( "RKExporter: unknown type. I only know about exporting recipes or cookbooks.")));
} // buildStringList()

/*!
  Puts the (text) contents of m_cookbook into m_lines.
*/
void
RKExporter::convertCookbook()
{
   createCookbookHeader();
   createRecipes();
} // convertCookbook()

void
RKExporter::createCookbookHeader()
{
   if ((m_type != COOKBOOK) || (m_cookbook->getRecipeList().size() <= 1))
      return;

   // Don't tr() this.
   QString titleline( "===== Titelliste (");
   titleline.append( QString::number( m_cookbook->getRecipeList().size()));
   titleline.append( " Rezepte) =====\n");
   m_lines << titleline;
   RecipeModel::RecipeList rl = m_cookbook->getRecipeList();
   RecipeModel::RecipeList::const_iterator it = rl.begin();
   while (it != rl.end()) {
      m_lines << (*it).title();
      it++;
   }
   m_lines << "";
} // createCookbookHeader()

void
RKExporter::createRecipes()
{
   RecipeModel::RecipeList rl = m_cookbook->getRecipeList();
   RecipeModel::RecipeList::const_iterator it = rl.begin();
   while (it != rl.end()) {
      m_recipe = (*it);
      convertRecipe();
      it++;
   }
} // createRecipes()

/*!
  Puts the (text) contents of m_recipe into m_lines.
*/
void
RKExporter::convertRecipe()
{
   createRecipeHeader();
   createRecipeBody();
} // convertRecipe()

void
RKExporter::createRecipeHeader()
{
   QString s( "===== REZKONV-Rezept - Mango v");
   s.append( MANGO_VERSION_STRING);
   s.append( "\n");
   m_lines << s;
} // createRecipeHeader()

void
RKExporter::createRecipeBody()
{
   QString s( "     Titel: ");
   s.append( m_recipe.title());
   m_lines << s;
   s = "Kategorien: ";
   s.append( m_recipe.categories().join( ", "));
   m_lines << s;
   s = "     Menge: ";
   int yield = m_recipe.yieldQty();
   s.append( QString::number( yield));
   s.append( " ");
   s.append( m_recipe.yieldUnit());
   m_lines << s << "";

   QStringList ingLines;

   // Handle a group with an eventually empty name first
   QString emptyString;
   Recipe::Ingredients::iterator aListIt = m_recipe.ingredients().find( emptyString);
   Recipe::IngredientList aList = aListIt.data();
   if (aList.count() > 0) ingLines += ingredientList2StringList( aList);

   Recipe::Ingredients ings = m_recipe.ingredients();
   Recipe::Ingredients::const_iterator it;
   for (it = ings.begin(); it != ings.end(); it++)
   {
      /*
        In case an ingredient group name is set, export it as:
        =======================NAME========================
        Line length is 60 chars max.
      */
      QString groupName( it.key());
      if (groupName.isEmpty()) {
         continue;              // next group, empty ones already handled
      } else {
         QString group( "=====");
         int fillchars = (60 - 5 - groupName.length()) / 2;
         for (int a = 0; a < (fillchars - 3); a++) group.append( "=");
         group.append( groupName);
         for (int b = 0; b < (fillchars + 2); b++) group.append( "=");
         ingLines << group;
      }

      // Now fetch the ingredient list of this group
      Recipe::IngredientList ingList = it.data();
      ingLines += ingredientList2StringList( ingList);
   }
   m_lines += ingLines;

   if (!m_recipe.source().isEmpty() || !m_recipe.typist().isEmpty() 
	   || !m_recipe.created().isNull() || !m_recipe.modified().isNull()) {
      QString str;
      QTextOStream( &str)
         << "\n=========================QUELLE=========================";
      m_lines << str;
   }
   if (!m_recipe.source().isEmpty()) {
      QString s( "                   -- ");
      s.append( m_recipe.source());
      m_lines << s;
   }
   if (!m_recipe.typist().isEmpty()) {
      QString s( "                   -- ");
      s.append( "Erfasst *RK* ");
      s.append( m_recipe.created().toString( "dd.MM.yy"));
      s.append( " von ");
      m_lines << s;
      s = "                   -- ";
      s.append( m_recipe.typist());
      m_lines << s;
   }
   m_lines << "";
   QStringList directionLines = wrapText( m_recipe.directions(), 72);
   m_lines += directionLines;
   m_lines << "\n=====\n";
} // createRecipeBody()

/*!
  amount: column 0-6
  measurement: column 8-17
  name: column: 19+
*/
QStringList
RKExporter::ingredientList2StringList( const Recipe::IngredientList& lst) const
{
   QStringList ret;
   Recipe::IngredientList::const_iterator it;
   for (it = lst.begin(); it != lst.end(); it++) {
      QString amtStr( QString::number( (*it).amountQty()));
      int fillchars = 7 - amtStr.length();
      QString fillStr;
      fillStr.fill( ' ', fillchars);
      amtStr.prepend( fillStr);

      QString meaStr = (*it).measurement().rkAbbrev();
      QString nameStr( (*it).name());
      /*
        There are some special words that might be placed in the name
        section. RezKonv recipes want them in the measurement instead.
      */
      if (nameStr.startsWith( "Würfel")) {
         meaStr.append( "Würfel");
         nameStr = nameStr.replace( QRegExp( "^Würfel"), "");
      }
      else if (nameStr.startsWith( "Handvoll")) {
         meaStr.append( "Handvoll");
         nameStr = nameStr.replace( QRegExp( "^Handvoll"), "");
      }
      else if (nameStr.startsWith( "Stücke")) {
         meaStr.append( "Stücke");
         nameStr = nameStr.replace( QRegExp( "^Stücke"), "");
      }
      else if (nameStr.startsWith( "Stück")) {
         meaStr.append( "Stück");
         nameStr = nameStr.replace( QRegExp( "^Stück"), "");
      }
      else if (nameStr.startsWith( "Stangen")) {
         meaStr.append( "Stangen");
         nameStr = nameStr.replace( QRegExp( "^Stangen"), "");
      }
      else if (nameStr.startsWith( "Stange/n")) {
         meaStr.append( "Stange/n");
         nameStr = nameStr.replace( QRegExp( "^Stange/n"), "");
      }
      else if (nameStr.startsWith( "Stange")) {
         meaStr.append( "Stange");
         nameStr = nameStr.replace( QRegExp( "^Stange"), "");
      }
      else if (nameStr.startsWith( "Stängel")) {
         meaStr.append( "Stängel");
         nameStr = nameStr.replace( QRegExp( "^Stängel"), "");
      }
      else if (nameStr.startsWith( "Zweige")) {
         meaStr.append( "Zweige");
         nameStr = nameStr.replace( QRegExp( "^Zweige"), "");
      }
      else if (nameStr.startsWith( "Zweig/e")) {
         meaStr.append( "Zweig/e");
         nameStr = nameStr.replace( QRegExp( "^Zweig/e"), "");
      }
      else if (nameStr.startsWith( "Zweig")) {
         meaStr.append( "Zweig");
         nameStr = nameStr.replace( QRegExp( "^Zweig"), "");
      }
      else if (nameStr.startsWith( "Blatt")) {
         meaStr.append( "Blatt");
         nameStr = nameStr.replace( QRegExp( "^Blatt"), "");
      }
      else if (nameStr.startsWith( "Blätter")) {
         meaStr.append( "Blätter");
         nameStr = nameStr.replace( QRegExp( "^Blätter"), "");
      }
      else if (nameStr.startsWith( "Kopf")) {
         meaStr.append( "Kopf");
         nameStr = nameStr.replace( QRegExp( "^Kopf"), "");
      }
      else if (nameStr.startsWith( "cm")) {
         meaStr.append( "cm");
         nameStr = nameStr.replace( QRegExp( "^cm"), "");
      }
      else if (nameStr.startsWith( "cm-Stück")) {
         meaStr.append( "cm-Stück");
         nameStr = nameStr.replace( QRegExp( "^cm-Stück"), "");
      }
      else if (nameStr.startsWith( "Einige")) {
         meaStr.append( "Einige");
         nameStr = nameStr.replace( QRegExp( "^Einige"), "");
      }
      else if (nameStr.startsWith( "Mehrere")) {
         meaStr.append( "Mehrere");
         nameStr = nameStr.replace( QRegExp( "^Mehrere"), "");
      }

      fillchars = 17 - 7 - meaStr.length();
      fillStr.truncate(0);
      fillStr.fill( ' ', fillchars);
      meaStr.prepend( fillStr);
      
      QString s;
      s.append( amtStr);           // col. 0..6
      s.append( " ");              // col. 7
      s.append( meaStr);           // col. 8..17
      s.append( " ");              // col. 18
      s.append( nameStr);          // col. 19+
      ret << s;
   }
   return ret;
} // ingredientList2StringList()
   
/*
  Wrap text \a str into several lines. Each line is wrapped at position \a at.
  \return stringlist containing a string for each line of text.
*/
QStringList
RKExporter::wrapText( const QString& str, const int at) const
{
   QStringList ret;
   QString copy( str);
   bool stop = false;
   while (!stop) {
      QString line( copy.left( at));
      if (line.length() >= copy.length()) stop = true;
      QRegExp rxp( "(\\s\\S*)$", false); // last word in the new line
      rxp.setMinimal( true);    // one word, no more.
      line = line.replace( rxp, ""); // remove last word
      copy = copy.remove( 0, line.length()); // did this line. cut it.
      line = line.simplifyWhiteSpace();
      ret << line;
   }
   return ret;
} //  wrapText()
