#!/usr/bin/perl -w
# $Id: mpm 195 2013-07-19 06:56:48Z minus $
use strict;

=encoding windows-1251

=head1 NAME

mpm - MPMinus helper

=head1 VERSION

Version 1.17

=head1 SYNOPSIS

    mpm [options] [commands [args]] 

    mpm [-cdlt]

    mpm [-h | -v | -m]

    mpm [--help | --version | --man]
    
    mpm [--log] [--debug] [--testmode] [-s sharedir]
        [ test | void | config [option [value]] | create [projectname] | 
          project projectname [operation [arg1]] ]

=head1 OPTIONS

=over 8

=item B<-c CONFFILE, --conffile=CONFFILE, --conf=CONFFILE, --config=CONFFILE>

     .   
    ,     
        CONFDIR.
     /etc/mpminus/mpm.conf

=item B<--confdir=CONFDIR>

         , 
    ,       .
        /etc/mpminus/conf

=item B<--datadir=DATADIR>

   .
          .     
 mpminus       

=item B<-d, --debug>

      CTK.
         .

=item B<-h, --help>

   .

=item B<-l, --log>

    (debug)     CTK.

=item B<--logdir=LOGDIR>

    .
   Windows -    Perl,  linux/unix -  /var/log

=item B<--logfile=LOGFILE>

    mpm.log.         , 
    mpm.log  LOGDIR

=item B<-m, --man>

   .

=item B<-s SHAREDIR, --sharedir=SHAREDIR, --share=SHAREDIR>

Share directory. Skeleton located in SHAREDIR/skel directory

=item B<-t, --testmode>

    .

=item B<-v, --ver, --version>

     .

=back

=head1 COMMANDS

=over 8

=item B<config>

    mpm config

  mpm -        .
     2 :      .  
       .       NULL ()

=item B<create>

    mpm create projectname

 .          Unix 

=item B<project>

    mpm project projectname

   projectname.    ,    

=item B<test>

    mpm test

   MPMinus

=item B<void>

    mpm void

 ,      .

    ,      
 CPAN    

=back

=head1 ABSTRACT

mpm - MPMinus helper

=head1 DESCRIPTION

    MPMinus

=head1 HISTORY

=over 8

=item B<1.00 / 21.04.2011>

Init version

=item B<1.01 / 21.12.2011>

      Apache    mpm

=item B<1.10 / 28.12.2011>

   

=item B<1.15 / Tue Jun  4 10:44:13 2013 GMT>

Init version as part of MPMinus

=back

See C<CHANGES> file

=head1 DEPENDENCIES

L<CTK>

=head1 TO DO

See C<TODO> file

=head1 BUGS

Coming soon

=head1 SEE ALSO

C<perl>, L<CTK>

=head1 DIAGNOSTICS

The usual warnings if it can't read or write the files involved.

=head1 AUTHOR

Serz Minus (Lepenkov Sergey) L<http://serzik.ru> E<lt>minus@mail333.comE<gt>

=head1 COPYRIGHT

Copyright (C) 1998-2013 D&D Corporation. All Rights Reserved

=head1 LICENSE

This program is distributed under the GNU GPL v3.

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 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

See C<LICENSE> file

=cut

use constant {
    PIDFILE   => 'mpm.pid', #  PID  
    PREFIX    => 'mpminus', #   
    SKELDIR   => 'src/skel',#     (  !!!)
    METAFILE  => 'META.yml',# META-

    #    .
    CMDDEFAULT => 'void',
    CMD => {
        void => {
            pidcheck => 0, # 0 - OFF, 1 - ON
        },
        test => {
            pidcheck => 1, # 0 - OFF, 1 - ON
        },
        config => {
            pidcheck => 1,
            sysconfdir => '',
        },
        create => {
            pidcheck => 1,
        },
        project => {
            pidcheck => 1,
        },
    },

};

use Getopt::Long;
use Pod::Usage;
use FindBin qw($RealBin);

# CTK Packages
use base qw/MPMinus::Helper::Handlers/;
use CTK;
use CTK::FilePid;

#  
Getopt::Long::Configure ("bundling");

GetOptions(\%OPT,

    #  
    "help|usage|h|?",                       #   
    "man|m",                                # 
    "version|ver|v",                        #  
    
    #  
    "debug|d",                              #  
    "log|l",                                #  --  ,   . LOG
   
    #  
    "testmode|test|t",                      #   

    #  
    "datadir=s",                            # DATADIR
    "logdir=s",                             # LOGDIR
    "logfile=s",                            # LOGFILE
    "conffile|conf|config|c=s",             # CONFFILE
    "confdir=s",                            # CONFDIR
    
    "sharedir|share|sd|s=s",                # SHAREDIR (For skel dir)
    
) || pod2usage(-exitval => 1, -verbose => 0, -output => \*CTK::CTKCP);
pod2usage(-exitval => 0, -verbose => 0, -output => \*CTK::CTKCP) if $OPT{help};
pod2usage(-exitval => 0, -verbose => 99, -sections => 'NAME|VERSION', -output => \*CTK::CTKCP) if $OPT{version};
pod2usage(-exitval => 0, -verbose => 2, -output => \*CTK::CTKCP) if $OPT{man};

# VARS
my %cmddata;

# 
my $command   = @ARGV ? shift @ARGV : CMDDEFAULT; # 
my @arguments = @ARGV ? @ARGV : (); #  
my @commands  = keys %{sub{CMD}->()}; # @{sub{COMMANDS}->()}
pod2usage(-exitval => 1, -verbose => 99, -sections => 'SYNOPSIS|OPTIONS|COMMANDS', -output => \*CTK::CTKCP)
    if ( (grep {$_ eq $command} @commands) ? 0 : 1 );

#    (DATADIR)   TEMP
$DATADIR = $OPT{datadir} || '';
$DATADIR = CTK::catfile(CTK::tmpdir(),PREFIX) unless $DATADIR;

#    (LOGDIR)   TEMP
$LOGDIR = $OPT{logdir} || CTK::syslogdir();
$LOGDIR = $LOGDIR = CTK::tmpdir() unless -e $LOGDIR;

#    (LOGFILE)   LOGDIR
$LOGFILE = $OPT{logfile} || '';
$LOGFILE = CTK::catfile($LOGDIR,"mpm.log") unless $LOGFILE;

#     (CONFDIR)   /etc    (CONFFILE)
my $SYSCONFDIR = CTK::sysconfdir(); #  
CMD->{config}{sysconfdir} = $SYSCONFDIR;
$CONFDIR = $OPT{confdir} || CTK::catfile($SYSCONFDIR,PREFIX,'conf');
$CONFFILE = $OPT{conffile} || CTK::catfile($SYSCONFDIR,PREFIX,'mpm.conf');

# Preparing directories
CTK::preparedir({
        logdir  => $LOGDIR,
        datadir => $DATADIR,
        confdir => $CONFDIR,
    });

# 
exception( "You must have specify valid temp directory to store temporary files ($DATADIR)" ) unless ($DATADIR && -d $DATADIR);
exception( "You must have specify valid log directory to store log files ($LOGDIR)" ) unless ($LOGDIR && -d $LOGDIR);
    
START:  debug "-"x16, " START ", (testmode() ? 'IN TEST MODE ' : ''), tms," ","-"x16;
#########################
### START
#########################

my $code = __PACKAGE__->can(uc($command));
if ($code && ref($code) eq 'CODE') {
    %cmddata = %{CMD->{$command}};
    $cmddata{arguments} = [@arguments];

    #  PID    
    my $pidfile = new CTK::FilePid({ file => CTK::catfile($DATADIR, $cmddata{pidfile} || PIDFILE) });
    my $pidstat = $pidfile->running || 0;
    
    debug "==== START COMMAND: ".uc($command)." ($$) ====";
    
    if ($cmddata{pidcheck}) {
        exception("PID STATE (".$pidfile->file()."): ALREADY EXISTS (PID: $pidstat)" ) if $pidstat;
        $pidfile->write;
    }

    &{$code}(%cmddata); #       
    
    if ($cmddata{pidcheck}) {
        $pidfile->remove;
    }
    
    debug "==== FINISH COMMAND: ".uc($command)." ($$) ====";
} else {
    exception("Sub \"".uc($command)."\" undefined");
}

#########################
### FINISH
#########################
FINISH: debug "-"x16, " FINISH ", (testmode() ? 'IN TEST MODE ' : '') ,tms," ","-"x16;
exit(0);

1;
__END__

NoUsed keys map:

a A b B   C   D e E 
f F g G   H i I j J 
k K   L   M n N o O 
p P q Q r R   S   T 
u U   V w W x X y Y 
z Z

