package Lab::XPRESS::Data::XPRESS_DataFile;
#ABSTRACT: XPRESS data file module
$Lab::XPRESS::Data::XPRESS_DataFile::VERSION = '3.630';
use strict;
use Time::HiRes qw/usleep/, qw/time/;
use Storable qw(dclone);
use File::Copy;
use Lab::XPRESS::Data::XPRESS_logger;
use Lab::XPRESS::Sweep;


our $counter        = 0;
our $GLOBAL_PATH    = "./";
our $GLOBAL_FOLDER  = undef;
our $DEFAULT_FOLDER = "MEAS";

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self  = {};
    bless( $self, $class );
    $self->{COLUMN_NAMES};
    $self->{NUMBER_OF_COLUMNS} = 0;
    $self->{COLUMNS}           = ();
    $self->{BLOCK_NUM}         = 0;
    $self->{LOG_STARTED}       = 0;
    $self->{loop}->{interval}  = 1;
    $self->{loop}->{overtime}  = 0;

    $self->{autolog} = 1;
    $self->{skiplog} = 0;

    my $filenamebase = shift;

    if ( not $filenamebase =~ /(.+)(\..+)\b/ ) {
        $filenamebase .= ".dat";
    }

    my $foldername = $DEFAULT_FOLDER;
    $foldername = shift if @_;

    $self->{filenamebase} = $filenamebase;

    my @plots = @_;
    $self->{plots} = [];
    foreach my $plot (@plots) {
        $self->add_plot($plot);
    }

    $self->{plot_count} = @plots;

    # create file-handle:
    $self->{filenamebase}
        = $self->create_folder( $self->{filenamebase}, $foldername );

    $self->open_logger( $self->{filenamebase}, $self->{plots} );
    $self->{file} = $self->{filenamebase};

    return $self;

}

sub create_folder {

    my $self         = shift;
    my $filenamebase = shift;
    my $foldername   = shift || $DEFAULT_FOLDER;

    $filenamebase =~ s/\\/\//g;
    $filenamebase =~ s/\.\///g;
    $filenamebase =~ s/\.\.\///g;
    $filenamebase =~ s/[a-zA-Z]\:\///g;

    my @filename = split( /\//, $filenamebase );
    my $filename = pop(@filename);

    my $folder = join( '/', @filename );

    if ( not defined $GLOBAL_FOLDER ) {
        if ( not -d $GLOBAL_PATH ) {
            mkdir $GLOBAL_PATH;
        }

        # look for existing files:
        opendir( DIR, $GLOBAL_PATH );
        my @files = readdir(DIR);

        my $max_index = 0;
        foreach my $file (@files) {

            if ( $file =~ /($foldername)_([0-9]+)\b/ ) {
                if ( $2 > $max_index ) {
                    $max_index = $2;
                }
                $max_index++;
            }
        }

        closedir(DIR);

        $GLOBAL_PATH =~ s/\/$//;
        $GLOBAL_FOLDER
            = sprintf( "%s/%s_%03d", $GLOBAL_PATH, $foldername, $max_index );

        mkdir($GLOBAL_FOLDER);

        copy( $0, $GLOBAL_FOLDER );

        $self->create_InfoFile();
    }

    my $folder = $GLOBAL_FOLDER . "/" . $folder;

    return $folder . "/" . $filename;

}

sub create_InfoFile {
    my $self = shift;

    open( my $LOG, ">" . $GLOBAL_FOLDER . "/Config.txt" )
        or die "cannot open Config.txt";
    print $LOG "Instrument Configuration\n";
    print $LOG "-" x 100, "\n\n";
    print $LOG $self->timestamp(), "\n";
    print $LOG "-" x 100, "\n\n";

    foreach my $instrument ( @{Lab::Instrument::REGISTERED_INSTRUMENTS} ) {
        print $LOG $instrument->get_id() . " ( "
            . $instrument->get_name()
            . " )", "\n\n";
        print $LOG $instrument->sprint_config(), "\n";
        print $LOG "-" x 100, "\n\n";
    }

}

# ------------------------------- CONFIG ---------------------------------------------------------
sub add_measurement {
    my $self    = shift;
    my $methode = shift;

    my $name = "measurement";
    $self->{measurement} = $methode;

    my $package = ref($self) . "_" . $counter++;

    no strict 'refs';
    *{ $package . "::" . $name } = $methode;
    @{ $package . '::ISA' } = ( ref($self) );
    bless $self, $package;

    return $self;
}

sub add_header {
    my $self   = shift;
    my $header = shift;

    if ( not defined $header ) {
        return $self->{HEADER};
    }

    my @header = split( /\n/, $header );
    foreach (@header) {
        $self->{HEADER} .= "#HEADER#\t" . $_ . "\n";
    }

    return $self;
}

sub add_config {
    my $self   = shift;
    my $config = shift;

    if ( not defined $config ) {
        return $self->{CONFIG};
    }

    my @config = split( /\n/, $config );
    foreach (@config) {
        $self->{HEADER} .= "#CONFIG#\t" . $_ . "\n";
    }

    return $self;
}

sub add_column {
    my $self = shift;
    my $col  = shift;

    if ( eval "return exists &Lab::XPRESS::Sweep::$col;" ) {
        Lab::Exception::Warning->throw(
            "$col is not an alowed column name. Sorry. \n");
    }

    if ( not defined $col ) {
        return $self->{COLUMNS};
    }

    $self->{COLUMN_NAMES}{$col}
        = scalar( keys %{ $self->{COLUMN_NAMES} } ) + 1;
    push( @{ $self->{COLUMNS} }, $col );
    $self->{NUMBER_OF_COLUMNS} += 1;
    $self->{logger}->{COLUMN_NAMES}      = $self->{COLUMN_NAMES};
    $self->{logger}->{NUMBER_OF_COLUMNS} = $self->{NUMBER_OF_COLUMNS};
    return $self;
}

sub add_plot {
    my $self = shift;
    my $plot;

    if ( ref( @_[0] ) eq 'HASH' ) {
        $plot = @_[0];
    }
    else {
        $plot = shift;
    }

    if ( not defined $plot->{'autosave'} ) {
        $plot->{'autosave'} = 'last';
    }
    push( @{ $self->{plots} }, $plot );
    $self->{logger}->{COLUMN_NAMES}
        = $self->{COLUMN_NAMES};    # refresh logger->column_names
    my $plot_copy = dclone( \%{$plot} );
    $self->{logger}->add_plots($plot_copy);
    $self->{plot_count}++;

    return $self;
}

sub open_logger {
    my $self         = shift;
    my $filenamebase = shift;
    my $plots        = shift;

    my $plots_copy = [];

    if ( defined $plots ) {
        my $plots_copy = dclone($plots);
    }

    $self->{logger}
        = new Lab::XPRESS::Data::XPRESS_logger( $filenamebase, $plots_copy );
    $self->{logger}->{COLUMN_NAMES} = $self->{COLUMN_NAMES};
}

sub change_filenamebase {
    my $self         = shift;
    my $filenamebase = shift;
    if ( not $filenamebase =~ /\// ) {
        $filenamebase = "./" . $filenamebase;
    }

    #$self->{filenamebase} = $filenamebase;

    my $old_file      = $self->{logger}->{filename};
    my $old_directory = $self->{logger}->{directory};

    delete $self->{logger};
    $self->{LOG_STARTED} = 0;

    if ( -z $old_file ) {
        unlink $old_file;
    }

    $self->open_logger($filenamebase);
    $self->{file} = $self->{logger}->{filename};

    $self->{logger}->{COLUMN_NAMES}      = $self->{COLUMN_NAMES};
    $self->{logger}->{NUMBER_OF_COLUMNS} = $self->{NUMBER_OF_COLUMNS};

    my $plots_copy = dclone( $self->{plots} );
    $self->{logger}->add_plots($plots_copy);

}

sub start_log {
    my $self = shift;

    if ( defined $self->{HEADER} ) {
        chomp $self->{HEADER};
        $self->{logger}->LOG( $self->{HEADER} );
    }
    if ( defined $self->{CONFIG} ) {
        $self->{logger}->LOG( $self->{CONFIG} );
    }
    if ( defined @{ $self->{COLUMNS} }[0] ) {
        my $columns = "#";
        $columns .= join( "\t", @{ $self->{COLUMNS} } );

        $self->{logger}->LOG($columns);
    }
    $self->{LOG_STARTED} = 1;
    return $self;
}

sub start_block {
    my $self = shift;

    if ( not $self->{LOG_STARTED} ) {
        $self->start_log();
    }

    $self->{BLOCK_NUM} = $self->{logger}->_log_start_block();
    print "Data block $self->{BLOCK_NUM}\n";

    $self->{loop}->{overtime} = 0;
    undef $self->{loop}->{t0};

    return 1;

}

sub set_loop_interval {
    my $self     = shift;
    my $interval = shift;

    $self->{loop}->{interval} = $interval;

    return $self;

}

sub end_loop {

    my $self = shift;

    $self->{loop}->{t1} = time();

    if ( not defined $self->{loop}->{t0} ) {
        $self->{loop}->{t0} = time();
        return 0;
    }

    my $delta_time = ( $self->{loop}->{t1} - $self->{loop}->{t0} )
        ;    # + $self->{loop}->{overtime};
    if ( $delta_time > $self->{loop}->{interval} ) {
        $self->{loop}->{overtime} = $delta_time - $self->{loop}->{interval};
        $delta_time = $self->{loop}->{interval};
        warn
            "WARNING: Measurement Loop takes more time ($self->{loop}->{overtime}) than specified by measurement interval ($self->{loop}->{interval}).\n";
    }
    else {
        $self->{loop}->{overtime} = 0;
    }
    usleep( ( $self->{loop}->{interval} - $delta_time ) * 1e6 );
    $self->{loop}->{t0} = time();
    return $delta_time;

}

sub timestamp {

    my $self = shift;
    my (
        $Sekunden, $Minuten,   $Stunden,   $Monatstag, $Monat,
        $Jahr,     $Wochentag, $Jahrestag, $Sommerzeit
    ) = localtime(time);

    $Monat     += 1;
    $Jahrestag += 1;
    $Monat     = $Monat < 10     ? $Monat     = "0" . $Monat     : $Monat;
    $Monatstag = $Monatstag < 10 ? $Monatstag = "0" . $Monatstag : $Monatstag;
    $Stunden   = $Stunden < 10   ? $Stunden   = "0" . $Stunden   : $Stunden;
    $Minuten   = $Minuten < 10   ? $Minuten   = "0" . $Minuten   : $Minuten;
    $Sekunden  = $Sekunden < 10  ? $Sekunden  = "0" . $Sekunden  : $Sekunden;
    $Jahr += 1900;

    return "$Stunden:$Minuten:$Sekunden  $Monatstag.$Monat.$Jahr\n";

}

sub finish_measurement {
    my $self = shift;

    my $num_of_plots = @{ $self->{logger}->{plots} };
    for ( my $i = 0; $i < $num_of_plots; $i++ ) {

        # close gnuplot-pipe:
        $self->{logger}->{plots}->[$i]->{plotter}->_stop_live_plot();
    }

    $self = $self->{logger}->close_file();

    delete $self->{logger};
    return $self;
}

sub save_plot {
    my $self       = shift;
    my $plot_index = shift;
    my $type       = shift;
    my $filename   = shift;

    if ( not defined $plot_index ) {
        $plot_index = 0;
    }
    elsif ( $plot_index > ( my $num_plots = @{ $self->{logger}->{plots} } ) )
    {
        warn "defined plotnumber $plot_index doesn't exist.";
    }

    if ( not defined $filename ) {

        # create filename for saving plot as eps-file:
        $filename = $self->{logger}->{filename};
        $filename =~ /(.+)\.(.+)\b/;
        $filename = sprintf( "%s_%02d", $1, $plot_index + 1 );
    }

    if ( not defined $type ) {
        $type = 'png';
    }

    $self->{logger}->{plots}->[$plot_index]->{plotter}->replot();
    $self->{logger}->{plots}->[$plot_index]->{plotter}
        ->save_plot( $type, $filename );

    return $self;

}

sub LOG {
    my $self = shift;

    if ( $self->{skiplog} == 1 ) {
        $self->{skiplog} = 0;
        return $self;
    }

    if ( not $self->{LOG_STARTED} ) {
        $self->start_log();
    }

    if ( ref( $_[0] ) eq "HASH" ) {
        $self->{logger}->LOG(@_);
    }
    else {
        $self->{logger}->LOG( \@_ );
    }

    return $self;
}

sub set_autolog {
    my $self  = shift;
    my $value = shift;

    $self->{autolog} = $value;

    return $self;
}

sub skiplog {
    my $self = shift;

    $self->{skiplog} = 1;

    return $self;
}

sub gnuplot_cmd {
    my $self       = shift;
    my $plot_index = shift;
    my $cmd        = shift;

    if ( not defined $cmd ) {
        $cmd        = $plot_index;
        $plot_index = 0;
    }

    if ( $plot_index > ( my $num_plots = @{ $self->{logger}->{plots} } ) ) {
        warn "defined plotnumber $plot_index doesn't exist.";
    }

    $self->{logger}->{plots}->[$plot_index]->{plotter}->gnuplot_cmd($cmd);

    return $self;

}

sub gnuplot_init_bindings {
    my $self = shift;

    foreach my $plot ( @{ $self->{logger}->{plots} } ) {
        $plot->{plotter}->init_gnuplot_bindings();
    }

    return 1;
}

sub gnuplot_restart {
    my $self = shift;

    my $i = 0;
    foreach my $plot ( @{ $self->{logger}->{plots} } ) {
        if ( $plot->{plotter}->{PAUSE} < 0 ) {
            $self->gnuplot_pause();
        }

        my $gpipe = $plot->{plotter}->{gpipe};
        if ( not defined $gpipe ) {
            $plot->{plotter} = new Lab::XPRESS::Data::XPRESS_plotter(
                $self->{logger}->{filename}, $plot );
            $plot->{plotter}->{ID}       = $i;
            $plot->{plotter}->{FILENAME} = $self->{logger}->{filename};
            $plot->{plotter}->{COLUMN_NAMES}
                = $self->{logger}->{COLUMN_NAMES};
        }
        elsif ( not( my $result = print $gpipe "" ) ) {
            $plot->{plotter} = new Lab::XPRESS::Data::XPRESS_plotter(
                $self->{logger}->{filename}, $plot );
            $plot->{plotter}->{ID}       = $i;
            $plot->{plotter}->{FILENAME} = $self->{logger}->{filename};
            $plot->{plotter}->{COLUMN_NAMES}
                = $self->{logger}->{COLUMN_NAMES};
        }

        $plot->{plotter}->init_gnuplot();
        $plot->{plotter}->init_gnuplot_bindings();
        $plot->{plotter}->start_plot( $self->{BLOCK_NUM} );

        if ( $plot->{plotter}->{PAUSE} > 0 ) {
            $self->gnuplot_pause();
        }

        $i++;
    }

    return 1;
}

sub gnuplot_pause {
    my $self = shift;

    foreach my $plot ( @{ $self->{logger}->{plots} } ) {
        $plot->{plotter}->toggle_pause();
    }

    return 1;
}

sub datazone {
    my $self       = shift;
    my $plot_index = shift;
    my $left       = shift;
    my $center     = shift;
    my $right      = shift;

    my $x_min;
    my $x_max;
    my $y_min;
    my $y_max;

    my %plot
        = %{ $self->{logger}->{plots}->[$plot_index]->{plotter}->{plot} };
    if ( not defined $plot{'x-min'} ) {
        $x_min = $self->{logger}->{DATA}[ $plot{'x-axis'} - 1 ][0];
    }
    else {
        $x_min = $plot{'x-min'};
    }
    if ( not defined $plot{'x-max'} ) {
        $x_max = $self->{logger}->{DATA}[ $plot{'x-axis'} - 1 ][1];
    }
    else {
        $x_max = $plot{'x-max'};
    }
    if ( not defined $plot{'y-min'} ) {
        $y_min = $self->{logger}->{DATA}[ $plot{'y-axis'} - 1 ][0];
    }
    else {
        $y_min = $plot{'y-min'};
    }
    if ( not defined $plot{'y-max'} ) {
        $y_max = $self->{logger}->{DATA}[ $plot{'y-axis'} - 1 ][1];
    }
    else {
        $y_max = $plot{'y-max'};
    }
    $self->{logger}->{plots}->[$plot_index]->{plotter}
        ->datazone( $x_min, $x_max, $y_min, $y_max, $left, $center, $right );

    return $self;

}

sub DESTROY {
    my $self = shift;
    if ( $self->{writer} ) {
        $self->finish_measurement();
    }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Lab::XPRESS::Data::XPRESS_DataFile - XPRESS data file module

=head1 VERSION

version 3.630

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2018 by the Lab::Measurement team; in detail:

  Copyright 2012       Stefan Geissler
            2013       Alois Dirnaichner, Andreas K. Huettel, Christian Butschkow, Stefan Geissler
            2014       Christian Butschkow
            2016       Simon Reinhardt
            2017       Andreas K. Huettel, Simon Reinhardt


This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
