package XXV::OUTPUT::Console;

use Text::ASCIITable;
use Locale::gettext;

use strict;

use Tools;
use vars qw($AUTOLOAD);

# ------------------
sub AUTOLOAD {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || {};
    my $params = shift || 0;

    my $name = (split('::', $AUTOLOAD))[-1];
    return  if($name eq 'DESTROY');

    $obj->message(gettext("Sorry, but this command is not available in this Interface!"));
}

# ------------------
sub new {
# ------------------
	my($class, %attr) = @_;
	my $self = {};
	bless($self, $class);

    $self->{handle} = $attr{'-handle'}
        || return error('No handle defined!');

    $self->{dbh} = $attr{'-dbh'}
        || return error('No DBH defined!');

    $self->{paths} = $attr{'-paths'}
        || return error('No Paths given!');

    $self->{term} = $attr{'-term'}
        || return error('No Term given!');

    $self->{TYP} = 'CONSOLE';

    $self->{maxwidth} = 30;

	return $self;
}

# ------------------
sub printout {
# ------------------
    my $obj = shift  || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');

    my $h = $obj->{handle};
    print $h $data."\n";
}

# ------------------
sub message {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');

    my $t = new Text::ASCIITable;
    $t->setCols(gettext('Message'));
    if(ref $data eq 'ARRAY') {
        map { $t->addRow($_) } @$data;
    } else {
        $t->addRow($data);
    }
    $obj->printout($t->draw());
}

# ------------------
sub push {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');

    $obj->printout($data);
}
# ------------------
sub msg {
# ------------------
    my $obj = shift  || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');
    my $err = shift || return $obj->message($data);

    $obj->err($data) if($err);
}

# ------------------
sub err {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');

    my $t = new Text::ASCIITable;
    $t->setCols(gettext('ERROR'));
    if(ref $data eq 'ARRAY') {
        map { $t->addRow($_) } @$data;
    } else {
        $t->addRow($data);
    }
    $obj->printout($t->draw());
}

# ------------------
sub menu {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');

    my $t = new Text::ASCIITable;
    $t->setCols(gettext('Module'),
                gettext('Short'),
                gettext('Name'),
                gettext('Description'));

    foreach my $line (@$data) {
        if(ref $line eq 'ARRAY') {
            $t->addRow(@$line);
        } else {
            $obj->printout($line);
        }
    }

    $obj->printout($t->draw());
}

# ------------------
sub littlemenu {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');

    my $text = $data->{title}."\n";
    $text .= gettext("Please use command and one of the following sectors:\n");
    $text .= join(', ', sort keys %{$data->{links}});

    $obj->message($text);
}

# ------------------
sub login {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');

    my $questions = [
        'Name' => {
            typ     => 'string',
            msg     => gettext("Username?"),
        },
        'Password' => {
            typ     => 'string',
            msg     => gettext("Password?"),
        },
    ];

    my $answer = $obj->question($data."\r\n", $questions);
    return $answer;
}


# ------------------
sub table {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');
    my $param = shift || 0;


    my $fields = (ref $data eq 'ARRAY') ?
            shift @$data :
        [
            gettext('Name'),
            gettext('Value')
        ];

    my $t = new Text::ASCIITable;
    $t->setOptions($param)
        if($param);
    $t->setCols(@$fields);
    map { $t->setColWidth($_, $obj->{maxwidth}) } @$fields;

    if(ref $data eq 'ARRAY') {
        foreach my $line (@$data) {
            if(ref $line eq 'ARRAY') {
                $t->addRow(@$line);
            } else {
                $obj->printout($line);
            }
        }
    } else {
        foreach my $name (sort keys %$data) {
            my $dspl = '';
            if(ref $data->{$name} eq 'HASH') {
                foreach (sort keys %{$data->{$name}}) {
                    $dspl .= sprintf("%s: %s\n", $_, $data->{$name}->{$_});
                }
            } else {
                $dspl = $data->{$name};
            }
            $t->addRow($name, $dspl);
        }
    }

    $obj->printout(
        $t->draw( ['.=','=.','-','-'],   # .=-----------=.
                  ['|','|','|'],         # | info | info |
                  ['|-','-|','=','='],   # |-===========-|
                  ['|','|','|'],         # | info | info |
                  ["'=","='",'-','-'],   # '=-----------='
                  ['|=','=|','-','+']    # rowseperator
                )
    );
}

# ------------------
sub question {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $title = shift || 0;
    my $questions = shift || return error ('No Data!' );
    my $erg = shift || {};

    my $quest;

    # Check Data
    if(ref $erg eq 'HASH' and ref $questions eq 'ARRAY' and exists $erg->{action}) {
        my $error;
        @$quest = @$questions;
        while (my ($name, $data) = splice(@$quest, 0, 2)) {
            # Required value ...
            $error = $data->{req}
                if($data->{req} and not $erg->{$name});

            # Check Callback
            if(exists $data->{check} and ref $data->{check} eq 'CODE' and not $error) {
                ($erg->{$name}, $error) = $data->{check}($erg->{$name}, $data, $erg);
            }

            # Check on directory
            if($data->{typ} eq 'dir' and $data->{required} and not -d $erg->{$name}) {
                ($erg->{$name}, $error) = (undef, sprintf(gettext("Directory '%s' is doesn't exist!"), $erg->{$name}));
            }

            # Check on file
            if($data->{typ} eq 'file' and $data->{required} and not -e $erg->{$name}) {
                ($erg->{$name}, $error) = (undef, sprintf(gettext("File '%s' is doesn't exist!"), $erg->{$name}));
            }

            if($error) {
                $obj->err(sprintf(gettext("ERROR in %s: %s"),$name, $error));
                last;
            }
        }
        unless($error) {
            delete $erg->{action};
            return $erg;
        }
    }

    $obj->printout("$title\n") if($title);
    if(ref $questions eq 'ARRAY') {
        while (my ($name, $data) = splice(@$questions, 0, 2)) {
            my $type = delete $data->{typ};
            $type ||= 'string';
            $erg->{$name} = $obj->$type($data);
        }
    } else {
        my $type = delete $questions->{typ};
        $type ||= 'string';
        $erg = $obj->$type($questions);
    }
    return $erg;
}

# ------------------
sub list {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data!' );
    my $t = $obj->{term};
    my $error;
    my $def;

    if(defined $data->{def}) {
    if(ref $data->{def} eq 'CODE') {
	$def = $data->{def}();
    } elsif(ref $data->{def} eq 'ARRAY') {
	$def = join(', ', @{$data->{def}});
    } else {
	$def = $data->{def};
    }}

    my $message = (defined $def) ? sprintf('%s [%s]: ', $data->{msg}, $def) : $data->{msg}.': ';

    while (defined (my $answer = $t->readline($message))) {
        $answer =~ s/[\r|\n]//sig;

        # Default value ...
        $answer = $data->{def}
            if(defined $data->{def} and not $answer);

        # List ...
        $error = sprintf(gettext("\nPlease use one of this list items:\n %s"), join(",\n", @{$data->{choices}}))
            unless(grep($_ eq $answer, @{$data->{choices}}));

        # Required value ...
        $error = $data->{req}
            if($data->{req} and not $answer);

        # Check Callback ...
        ($answer, $error) = $data->{check}($answer)
            if(defined $data->{check} and ref $data->{check} eq 'CODE');

        # Display Error Message ....
        if($error) {
            $message = (defined $data->{def}) ? sprintf('%s [%s]', $error, $def) : $error.': ';
            undef $error;
        } else {
            return $answer;
        }
    }
}


# ------------------
sub string {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data!' );
    my $t = $obj->{term};
    my $error;

    my $def;
    if(defined $data->{def}) {
    if(ref $data->{def} eq 'CODE') {
	$def = $data->{def}();
    } else {
	$def = $data->{def};
    }}

    my $message = (defined $def) ? sprintf('%s [%s]: ', $data->{msg}, $def) : $data->{msg}.': ';
    while (defined (my $answer = $t->readline($message))) {
        $answer =~ s/[\r|\n]//sig;
        # Default value ...
        $answer = $def
            if($def and not $answer);

        # Required value ...
        $error = $data->{req}
            if($data->{req} and not $answer);

        # Check Callback ...
        ($answer, $error) = $data->{check}($answer)
            if(defined $data->{check} and ref $data->{check} eq 'CODE');

        # Display Error Message ....
        if($error) {
            $message = ($def) ? sprintf('%s [%s]', $error, $def) : $error.': ';
            undef $error;
        } else {
            return $answer;
        }
    }
}

# ------------------
sub file {
# ------------------
    my $obj = shift || return error ('No Object!' );
    return $obj->string(@_);
}

# ------------------
sub dir {
# ------------------
    my $obj = shift || return error ('No Object!' );
    return $obj->string(@_);
}

# ------------------
sub password {
# ------------------
    my $obj = shift || return error ('No Object!' );
    return $obj->string(@_);
}

# ------------------
sub integer {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data!' );
    my $t = $obj->{term};
    my $error;

    my $message = (defined $data->{def} ) ? sprintf('%s [%s]: ', $data->{msg}, $data->{def}) : $data->{msg}.': ';
    while (defined (my $answer = $t->readline($message))) {
        $answer =~ s/[\r|\n]//sig;

        # Default value ...
        $answer = $data->{def}
            if($data->{def} and ! $answer);

        # Interger?
        $error = sprintf(gettext("'%s' is not an integer!"),$answer)
            if($answer and not int($answer));

        # Required?
        $error = $data->{req}
            if(defined $data->{req} and not $answer);

        # Check Callback
        ($answer, $error) = $data->{check}($answer)
            if(defined $data->{check} and ref $data->{check} eq 'CODE');

        if($error) {
            $message = (defined $data->{def}) ? sprintf('%s [%s]', $error, $data->{def}) : $error.': ';
            undef $error;
        } else {
            return $answer;
        }
    }
}

# ------------------
sub confirm {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data!' );
    my $t = $obj->{term};
    my $error;

    my $message = (defined $data->{def} ) ? sprintf('%s [%s]: ', $data->{msg}, $data->{def}) : $data->{msg}.': ';
    while (defined (my $answer = $t->readline($message))) {
        $answer =~ s/[\r|\n]//sig;

        # Default value ...
        $answer = $data->{def}
            if($data->{def} and ! $answer);

        # Only yes or no ...
        $error = gettext("Please answer with 'y'es or 'n'o: ")
            if($answer !~ /^[y|n]$/);

        # Required value ...
        $error = $data->{req}
            if($data->{req} and not $answer);

        # Check Callback ...
        ($answer, $error) = $data->{check}($answer)
            if(defined $data->{check} and ref $data->{check} eq 'CODE');

        # Display Error Message ....
        if($error) {
            $message = (defined $data->{def}) ? sprintf('%s [%s]', $error, $data->{def}) : $error.': ';
            undef $error;
        } else {
            return $answer;
        }
    }
}

# ------------------
sub hidden {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data!' );

    return error('No <def> in hidden Variable!')
        unless(defined $data->{def});
    return $data->{def};
}

# ------------------
sub image {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data to display');

    return $obj->message(gettext("Sorry, but i cannot display an image on this Interface."));
}

# ------------------
sub checkbox {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data!' );
    my $t = $obj->{term};
    my $error;

    my $message = (defined $data->{def}) ? sprintf('%s [%s]: ', $data->{msg}, join(', ', @{$data->{def}})) : $data->{msg}.': ';
    while (defined (my $answer = $t->readline($message))) {
        $answer =~ s/[\r|\n]//sig;
        # Default value ...
        $answer = $data->{def}
            if(defined $data->{def} and not $answer);

        # Required value ...
        $error = $data->{req}
            if($data->{req} and not $answer);

        # Check Callback ...
        ($answer, $error) = $data->{check}($answer, $data)
            if(defined $data->{check} and ref $data->{check} eq 'CODE');

        # Display Error Message ....
        if($error) {
            $message = (defined $data->{def}) ? sprintf('%s [%s]', $error, join(', ', @{$data->{def}})) : $error.': ';
            undef $error;
        } else {
            return $answer;
        }
    }
}

# ------------------
sub radio {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $data = shift || return error ('No Data!' );
    my $t = $obj->{term};
    my $error;

    my $message = (defined $data->{def}) ? sprintf('%s [%s]: ', $data->{msg}, $data->{def}) : $data->{msg}.': ';
    while (defined (my $answer = $t->readline($message))) {
        $answer =~ s/[\r|\n]//sig;
        # Default value ...
        $answer = $data->{def}
            if(defined $data->{def} and not $answer);

        # Required value ...
        $error = $data->{req}
            if($data->{req} and not $answer);

        # only one of all ...
        $error = sprintf(gettext("You can only use one of this items: %s"), join(',', @{$data->{choices}}))
            unless(grep( $answer eq $_, @{$data->{choices}}));


        # Check Callback ...
        ($answer, $error) = $data->{check}($answer, $data)
            if(defined $data->{check} and ref $data->{check} eq 'CODE');

        # Display Error Message ....
        if($error) {
            $message = (defined $data->{def}) ? sprintf('%s [%s]', $error, $data->{def}) : $error.': ';
            undef $error;
        } else {
            return $answer;
        }
    }
}

# ------------------
sub pod {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $modname = shift || return error ('No Modname!' );

    my $podfile = sprintf('%s/%s.pod', $obj->{paths}->{DOCPATH}, $modname);
    my $txt = `pod2text --cachedir=/tmp $podfile`;
    $obj->message($txt);;
}

# ------------------
sub remote {
# ------------------
    my $obj = shift || return error ('No Object!' );

    my $text = qq!
.-----------------------.
| 1     | 2     | 3     |
|-----------------------|
| 4     | 5     | 6     |
|-----------------------|
| 7     | 8     | 9     |
|-----------------------|
| Menu  | 0     | Back  |
|-----------------------|
|       | Up    |       |
|-----------------------|
| Left  | Ok    | Right |
|-----------------------|
|       | Down  | Blue  |
|-----------------------|
| Red   | Green | Yellow|
|-----------------------|
| Vol:+/-   | Chan: <>  |
|-----------------------|
| <<        | >>        |
|-----------------------|
!;
    $obj->printout($text);
}

# ------------------
sub typ {
# ------------------
    my $obj = shift || return error ('No Object!');
    return $obj->{TYP};
}

1;
