package ARFF::Util;

use strict;

use Carp qw(cluck);

use Data::Dumper;
use Devel::Size qw(size total_size);
use String::Util ':all';

# version
use vars '$VERSION';

$VERSION = '1.00';


=head1 NAME

ARFF::Util -- ARFF files processing utilities

=head1 SYNOPSIS

  use ARFF::Util;
  
  # load .arff formatted file into the buffer, and return pointer to buffer
  $arff_hash = load_arff($file_address);
  
  # save given buffer into the .arff formatted file
  save_arff($arff_hash, $file_address);

=head1 DESCRIPTION

ARFF::Util provides a collection of methods for processing ARFF formatted files.
"An ARFF (Attribute-Relation File Format) file is an ASCII text file that describes a list of instances sharing a set of attributes."
for more information about ARFF format visit http://weka.sourceforge.net/wekadoc/index.php/en:ARFF_%283.5.1%29

=head1 FUNCTIONS

=cut




#------------------------------------------------------------------------------
# export
# 
use vars qw[@EXPORT_OK %EXPORT_TAGS @ISA];
@ISA = 'Exporter';

# the following functions accept a value and return a modified version of that value
push @EXPORT_OK, qw[
	load_arff     save_arff
];
#save_sql     save_xml	get_attributes     get_records

%EXPORT_TAGS = ('all' => [@EXPORT_OK]);


# 
# This is a buffer hash
# Structure of hash:
# relation -> {
#		attributes => [
#				{
#					attribute_name => x1,
#					attribute_type => x2,
#				},...
#			      ]
#		records    => [
#				{
#					attribute_name1 => value1,
#					attribute_name2 => value2,...
#				},...
#			      ]
#		data_record_count => x
#	      }
#
my $relation;

my $error_count = 0;
sub log_msg
{
	my ($msg) = @_;
	cluck $msg;
}
sub throw_error
{
	my ($msg) = @_;
	log_msg("Error occured : ".$msg);
	$error_count++;
}

# return size of buffer in bytes
sub get_buffer_size
{
  return total_size($relation);
}

# 
# export
#------------------------------------------------------------------------------


#------------------------------------------------------------------------------
# load_from_file
# 

=head1 load_from_file($filename)

Get arff file path and load it in buffer

=cut


sub load_from_file {
	my ($arff_file) = @_;
	local *FILE;
	open(FILE, $arff_file);
	my $status = q/normal/;
 	log_msg("Loading $arff_file ...");
	my $record_count = 0;
	my $attribute_count = 0;
	my $line_counter = 1;

	while (my $current_line = <FILE>)
	{
		$current_line = trim($current_line);
		#Check for comments
		if ($current_line =~ /^\s*%/i)
		{
			$status = q/comment/;
		}
		elsif ($current_line =~ /^\s*\@RELATION\s+(\S*)/i )
		{
			$relation -> {"relation_name"} = $1;
		}
		elsif ($current_line =~ /^\s*\@ATTRIBUTE\s+(\S*)\s+(\S*)/i )
		{
			if(!$relation -> {"attributes"}){
				$relation -> {"attributes"} = [];
			}
			my $attribute = { "attribute_name" => $1, "attribute_type" => $2};
			my $attributes = $relation -> {"attributes"};
 			#log_msg(Dumper $attribute);

			push  @$attributes , $attribute;
			$attribute_count ++;
		}
		elsif ($current_line =~ /^\s*\@DATA(\.*)/i )
		{
			$status = q/data/;
		}
		elsif($status == q/data/ && $current_line != q//){
			if(!$relation -> {"records"}){
				$relation -> {"records"} = [];
			}
			#log_msg("extracting data $current_line");
			my @data_parts = split(/,/, $current_line);

			my $attributes = $relation -> {"attributes"};
 			my $records = $relation -> {"records"};

			my $cur_record={};

 			#log_msg("DATA PARTS".Dumper @data_parts);
			if(scalar @data_parts == $attribute_count){
				for(my $i=0;$i<=$#data_parts;$i++)
				{
					$cur_record->{$$attributes[$i]->{"attribute_name"}} = trim($data_parts[$i]);
				}
				#log_msg("parts: ".$#data_parts);
	
				$record_count ++;
				push  @$records , $cur_record;
			}else
			{
				throw_error("Line $line_counter : Invalid data record: $current_line Containts ".(scalar @data_parts)." Expected $attribute_count");
			}
			
		}
		$line_counter ++;
	}
	
	$relation -> {"data_record_count"} = $record_count;
 	$relation -> {"attribute_count"} = $attribute_count;
 	#log_msg(Dumper $relation);
	log_msg("$arff_file loaded with $error_count error(s).");
	log_msg("Buffer size: ".get_buffer_size()."bytes");
	return 1;
}

load_from_file("c-train.arff");

# 
# crunch
#------------------------------------------------------------------------------


#------------------------------------------------------------------------------
# save_arff
# 

=head1 save_arff($buffer,$filename)

save given buffer into the .arff formatted file. This method is not implemented yet.


=cut

sub save_arff {
	my ($buffer,$file_name) = @_;
	
	throw_error("Not implemented yet!");
	
	return 1;
}
# 
# hascontent
#------------------------------------------------------------------------------



# return true
1;


__END__

=head1 TERMS AND CONDITIONS

Copyright (c) 2008 by Ehsan Emadzadeh.  All rights reserved.  This program is 
free software; you can redistribute it and/or modify it under the same terms 
as Perl itself. This software comes with B<NO WARRANTY> of any kind.

=head1 AUTHORS

Ehsan Emadzadeh
<ehsan0emadzadeh@yahoo.com>


=head1 VERSION

=over

=item Version 1.00    October 20, 2008

Initial release.
load_arff implemented





=back


=cut
