#=============================================================================
# Doloforge::Service::Project : generic configuration for any client/project
#
# Generate config files from templates, for all config file which
# do not really fit in a specific service:
#   read each template from [client]/[project]/conf/
#   if the template or the project config file is newer than the merged template
#   then re-merge the template and the config...
#   and write the result in [client]/[project]/_conf/gen/
#
# Full help :
#   perldoc Doloforge::Service::Project
#=============================================================================


package Doloforge::Service::Project;

use strict;

# This base class implements the constructor and help methods in a generic way.
use base qw(Doloforge::Service);


#=============================================================================
=encoding utf8

=head1 NAME

Doloforge::Service::Project : Generic configuration for any client/project

=head1 SYNOPSIS

    # Update the full configuration, running each client/project/service update
    doloforge config --update

=head1 DESCRIPTION

Todo

=cut


#=============================================================================
# Method update
#
# Update the service configuration on the host, depending on
# client/project/service config files...
# This method receives :
#   option: context options (mainly stage in which the client/project is evaluated
#   client_conf: client configuration file contents (client.$name.yaml)
#   project_conf: project configuration file contents (project.$name.client.$name.yaml)

sub update {
    my $self = shift;

    my ($option, $client_conf, $project_conf) = @_;

    # Read each available template file (*.tmpl) in the shared [client]/[project]/_conf/ directory
    # We use shared storage, so only NFS server should actually do that.
    if ($self->has_role('nfs_role')) {
        # FIXME : even with --force, should prevent a $merged file to be generated more than once (ie. with the apache service, and then with the project service)
        my $template_glob = "$self->{global}->{dir}->{shared}/$client_conf->{name}/$project_conf->{name}/conf/*.tmpl";
        $self->debug("reading glob '$template_glob'");
        foreach my $template (glob($template_glob)) {
            # Once merged, template files will be saved in _conf/ instead of conf/, without their trailing ".tmpl"
            my $merged = $template;
            $merged =~ s/\/conf\/([^\/]+)\.tmpl$/\/_conf\/$1/;

            # Actually merge the config hashes and the file, and save the result
            # Since we are currently handling alternate templates, there is non "alternate" parameter to the call (replaced by "undef")
            $self->merge_template($option, $client_conf, $project_conf, $template, undef, $merged);
        }
    }

    # The folowing merged templates are all stored on shared storage, so only generated by the NFS servers
    if ($self->has_role('nfs_role')) {
        # Merge the config hashes with the proper template files, and save the result...
        if ($self->merge_template($option, $client_conf, $project_conf, # Configuration hashes
            # Service-specific template, from [skel]/template/[stage]/cron_*
            "$self->{global}->{dir}->{skel}/template/$self->{name}_env.yaml.tmpl",
            # Alternate project-service-specific template, to be used if it exists
            "$self->{global}->{dir}->{shared}/$client_conf->{name}/$project_conf->{name}/conf/$self->{name}_env.yaml.tmpl",
            # Filled-in file, in [client]/[project]/_conf/ (it's name must be unique among all services)
            "$self->{global}->{dir}->{shared}/$client_conf->{name}/$project_conf->{name}/_conf/$self->{name}_env.yaml",
            # Link to the filled-in file, which must be maintained once the project is active
            undef,
        )) {
            # If the project_env.yaml file was actually generated, use it as a base for other formats of the same data...
            my $basename = "$self->{global}->{dir}->{shared}/$client_conf->{name}/$project_conf->{name}/_conf/$self->{name}_env";
            my $env = Config::YAML->new(config => "$basename.yaml");

            # Each key of the environment configuration file becomes an environment variable, except for keys starting with an underscore
            my @bash_env = ("# BASH definition of the environment variables describing the project", "# See $basename.yaml for details");
            my @perl_env = ("# PERL definition of the environment variables describing the project", "# See $basename.yaml for details");
            my @pm_env = ("# PERL module definition of the environment variables describing the project", "# See $basename.yaml for details");
            my @php_env = ("# PHP definition of the constants describing the project", "# See $basename.yaml for details");
            foreach my $key (sort(keys(%{$env}))) {
                # Environment variable don't have names starting with an "_"
                next if ($key =~ m/^_/);
                my $value;

                # Properly encode the value, regarding the context, as in a BASH "VAR='value'" line
                $value = $env->{$key};
                $value =~ s/\'/\'\"\'\"\'/g;
                push(@bash_env, "export $key='$value'");

                # ...now as in a PERL "$ENV{'VAR'}='value';" line
                $value = $env->{$key};
                $value =~ s/\'/\'/g;
                push(@perl_env, "\$ENV\{'$key'\}='$value';");
                # ...and again as a PERL hash value line
                push(@pm_env, "\t'$key' => '$value',");
                # ...and again as in a PHP "define('VAR', 'value');" line
                push(@php_env, "define('$key', '$value');");
            }
            # Add the special post-fix keys
            push(@bash_env, $env->{_bash_post}) if (exists($env->{_bash_post}));
            push(@perl_env, $env->{_perl_post}) if (exists($env->{_perl_post}));
            push(@pm_env, $env->{_pm_post}) if (exists($env->{_pm_post}));
            push(@php_env, $env->{_php_post}) if (exists($env->{_php_post}));
           
            # Write out each version of the environment variable file
            $self->write_file($option->{diff}, "$basename.sh", @bash_env);
            $self->write_file($option->{diff}, "$basename.pl", @perl_env);
            $self->write_file($option->{diff}, "$basename.pm", 'return {', @pm_env, '};');
            $self->write_file($option->{diff}, "$basename.php", "<?php", @php_env, "?>");
        }
    }
}


#=============================================================================
# Method finish
#
# Called when the whole processing is finished, when it's time to reload services.
# This generic class will do nothing special...

sub finish {
    my $self = shift;

    $self->warn("Modified $self->{modified} files")
        if ($self->{modified} > 0);
}



1;
__END__

=head1 AUTHOR

Nicolas Huillard <F<nicolas@huillard.net>>, Dolomède

=head1 SEE ALSO

doloforge(1)

=cut
