/***************************************************************************
*   Copyright (C) 2003 by                                                 *
*   Jason Kivlighn (jkivlighn@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 "nycgenericimporter.h"

#include <tdeapplication.h>
#include <tdelocale.h>
#include <kdebug.h>

#include <tqfile.h>
#include <tqtextstream.h>
#include <tqstringlist.h>
#include <tqregexp.h>

#include "datablocks/mixednumber.h"
#include "datablocks/recipe.h"

NYCGenericImporter::NYCGenericImporter() : BaseImporter()
{}

void NYCGenericImporter::parseFile( const TQString &file )
{
	first = true;

	m_recipe.empty();

	TQFile input( file );
	if ( input.open( IO_ReadOnly ) ) {
		TQTextStream stream( &input );
		stream.skipWhiteSpace();

		if ( !stream.atEnd() && stream.readLine().startsWith( "@@@@@" ) )
			importNYCGeneric( stream );
		else {
			setErrorMsg( i18n( "File does not appear to be a valid NYC export." ) );
			return ;
		}
	}
	else
		setErrorMsg( i18n( "Unable to open file." ) );
}

NYCGenericImporter::~NYCGenericImporter()
{}

void NYCGenericImporter::importNYCGeneric( TQTextStream &stream )
{
	tdeApp->processEvents(); //don't want the user to think its frozen... especially for files with thousands of recipes

	TQString current;

	stream.skipWhiteSpace();

	//title
	while ( !( current = stream.readLine() ).isEmpty() && !stream.atEnd() )
		m_recipe.title = current;

	//categories
	while ( !( current = stream.readLine() ).isEmpty() && !stream.atEnd() ) {
		if ( current[ 0 ].isNumber() ) {
			loadIngredientLine( current );
			break;
		} //oops, this is really an ingredient line (there was no category line)

		TQStringList categories = TQStringList::split( ',', current );

		if ( categories.count() > 0 && categories[ 0 ].upper() == "none" )  //there are no categories
			break;

		for ( TQStringList::const_iterator it = categories.begin(); it != categories.end(); ++it ) {
			Element new_cat( TQString( *it ).stripWhiteSpace() );
			kdDebug() << "Found category: " << new_cat.name << endl;
			m_recipe.categoryList.append( new_cat );
		}
	}

	//ingredients
	while ( !( current = stream.readLine() ).isEmpty() && !stream.atEnd() )
		loadIngredientLine( current );

	//everything else is the instructions with optional "contributor", "prep time" and "yield"
	bool found_next;
	while ( !( found_next = ( current = stream.readLine() ).startsWith( "@@@@@" ) ) && !stream.atEnd() ) {
		if ( current.startsWith( "Contributor:" ) ) {
			Element new_author( current.mid( current.find( ':' ) + 1, current.length() ).stripWhiteSpace() );
			kdDebug() << "Found author: " << new_author.name << endl;
			m_recipe.authorList.append( new_author );
		}
		else if ( current.startsWith( "Preparation Time:" ) ) {
			m_recipe.prepTime = TQTime::fromString( current.mid( current.find( ':' ), current.length() ) );
		}
		else if ( current.startsWith( "Yield:" ) ) {
			int colon_index = current.find( ':' );
			int amount_type_sep_index = current.find(" ",colon_index+1);

			m_recipe.yield.amount = current.mid( colon_index+2, amount_type_sep_index-colon_index ).toDouble();
			m_recipe.yield.type = current.mid( amount_type_sep_index+3, current.length() );
		}
		else if ( current.startsWith( "NYC Nutrition Analysis (per serving or yield unit):" ) ) {
			//m_recipe.instructions += current + "\n";
		}
		else if ( current.startsWith( "NYC Nutrilink:" ) ) {
			//m_recipe.instructions += current + "\n";
		}
		else if ( !current.stripWhiteSpace().isEmpty() && !current.startsWith("** Exported from Now You're Cooking!") ) {
			m_recipe.instructions += current + "\n";
		}
	}

	m_recipe.instructions = m_recipe.instructions.stripWhiteSpace();
	putDataInRecipe();

	if ( found_next )
		importNYCGeneric( stream );
}

void NYCGenericImporter::putDataInRecipe()
{
	//put it in the recipe list
	add( m_recipe );

	//reset for the next recipe
	m_recipe.empty();
}

void NYCGenericImporter::loadIngredientLine( const TQString &line )
{
	TQString current = line;

	if ( current.contains( "-----" ) ) {
		current_header = current.stripWhiteSpace();
		kdDebug() << "Found ingredient header: " << current_header << endl;
		return ;
	}

	MixedNumber amount( 0, 0, 1 );
	TQString unit;
	TQString name;
	TQString prep;

	TQStringList ingredient_line = TQStringList::split( ' ', current );

	bool found_amount = false;

	if ( !ingredient_line.empty() )  //probably an unnecessary check... but to be safe
	{
		bool ok;
		MixedNumber test_amount = MixedNumber::fromString( ingredient_line[ 0 ], &ok, /* locale_aware = */ false );
		if ( ok )
		{
			amount = amount + test_amount;
			ingredient_line.pop_front();
			found_amount = true;
		}
	}
	if ( !ingredient_line.empty() )  //probably an unnecessary check... but to be safe
	{
		bool ok;
		MixedNumber test_amount = MixedNumber::fromString( ingredient_line[ 0 ], &ok, /* locale_aware = */ false );
		if ( ok )
		{
			amount = amount + test_amount;
			ingredient_line.pop_front();
			found_amount = true;
		}
	}

	if ( found_amount ) {
		unit = ingredient_line[ 0 ];
		ingredient_line.pop_front();
	}

	//now join each separate part of ingredient (name, unit, amount)
	name = ingredient_line.join( " " );

	int prep_sep_index = name.find( TQRegExp( "(--|,;;)" ) );
	if ( prep_sep_index == -1 )
		prep_sep_index = name.length();

	name = name.left( prep_sep_index ).stripWhiteSpace();
	prep = name.mid( prep_sep_index+1, name.length() ).stripWhiteSpace();

	Ingredient new_ingredient( name, amount.toDouble(), Unit( unit, amount.toDouble() ) );
	new_ingredient.group = current_header;
	new_ingredient.prepMethodList = ElementList::split(",",prep);
	m_recipe.ingList.append( new_ingredient );

}

