package Cpanel::Easy::PHP5;

# cpanel - Cpanel/Easy/PHP5.pm                     Copyright(c) 2015 cPanel, Inc.
#                                                            All rights Reserved.
# copyright@cpanel.net                                          http://cpanel.net
# This code is subject to the cpanel license. Unauthorized copying is prohibited

use base 'Cpanel::Easy';

use Cpanel::Version::Compare             ();
use Cpanel::Version::Tiny                ();
use Cpanel::Easy::Apache::Utils::Support ();
use Cpanel::Easy::Utils                  ();
use Cpanel::Sys::OS                      ();

our @versions;

our %support_hash = (
    '3_29' => { support    => $Cpanel::Easy::Apache::Utils::Support::ENDOFLIFE },
    '4_45' => { min_cpanel => '11.32', support => $Cpanel::Easy::Apache::Utils::Support::ENDOFLIFE },
    '5_38' => { min_cpanel => '11.38', support => $Cpanel::Easy::Apache::Utils::Support::ENDOFLIFE },
    '6_39' => { min_cpanel => '11.38', default => 1, support => $Cpanel::Easy::Apache::Utils::Support::NORMAL },
);

our $easyconfig = {
    'name' => 'PHP 5',
    'note' => 'The current as recommended by the PHP Project. Performance and Security improvements over PHP 4.x',
};

# NOTE: Don't depend on the $self argument, Cpanel::Easy::Utils::NameSpace::get_std_variation_of_ns_list
# doesn't properly send a blessed object.  Instead it passes a scalar string value from the
# 'working_profile'.
sub versions {
    unless (@versions) {
        local $_;
        @versions = sort grep { is_php_available($_) } keys %support_hash;
    }
    return @versions;
}

sub oldest_version {
    return ( versions() )[0];
}

# Latest version, excluding 'experimental' versions
# Case 107457:  We are going to continue to default to 5.4, since 5.5 is still
# "newish", and not everything supports it.
sub latest_version {
    my ( $self, $profile_hr ) = @_;

    my $phpversion;
    my @versions;

    if ($profile_hr) {
        if ( is_php_enabled($profile_hr) ) {
            @versions = sort( get_profile_php_versions($profile_hr) );

            # user specified an available PHP version
            if (@versions) {
                $phpversion = $versions[-1];
            }

            # user didn't specify any PHP versions, or no good ones, so now
            # we need to pick one of the available
            else {
                @versions = reverse versions();
            }
        }
        else {
            # php isn't enabled, this will fall through below
        }
    }
    else {
        @versions = reverse versions();
    }

    # couldn't find latest version in profile, find the default
    if ( !$phpversion ) {
        my $version;

        # find latest available PHP version. but if multiple
        # are available, prefer the default version
        for my $ver (@versions) {
            if ( $support_hash{$ver}{support} ne $Cpanel::Easy::Apache::Utils::Support::EXPERIMENTAL ) {

                $version = $ver if !$version;

                if ( $support_hash{$ver}{default} ) {
                    $version = $ver;
                    last;
                }
            }
        }

        $phpversion = $version;
    }

    return $phpversion;
}

sub support_level {
    my $version = shift;
    my $level;

    if ( $version =~ /\b(\d+)[._](\d+)$/ ) {
        $version = normalize_php_version( $1 . '_' . $2 );
        $level   = $support_hash{$version}{support};
    }

    return $level;
}

sub support_decoration {
    my $support_level = support_level(@_);
    return Cpanel::Easy::Apache::Utils::Support::get_short_deco($support_level);
}

sub support_text {
    my $support_level = support_level(@_);
    return Cpanel::Easy::Apache::Utils::Support::get_long_deco($support_level);
}

sub is_top_ns_version {
    goto &Cpanel::Easy::Utils::PHP::is_top_ns_version;
}

# Determines if a PHP version is "Defined" and "Available" to the user.
#
# If version is available, it returns the normalized version.
# If version is unavailable, it returns undef.

# NOTE: Normally, each optmod is responsible for updating it's 'skip'
# value to designate whether or not it's available.  for some reason, we
# don't do that with PHP.  Not going to re-architect all of that now.
sub is_php_available {
    my $version = shift;
    my $available;

    my $norm = normalize_php_version($version);

    # if php version defined in EA3, now if it's supported
    if ( defined $norm && defined $support_hash{$norm} ) {
        my $h = $support_hash{$norm};

        $available = $norm;    # there's an entry in hash, must be supported

        # but there's a cpanel version requirement
        if ( defined $h->{min_cpanel} ) {
            $available = undef if Cpanel::Version::Compare::compare( $Cpanel::Version::Tiny::VERSION_BUILD, '<', $h->{min_cpanel} );
        }

        # and a minimum centos version requirement
        if ( defined $h->{min_centos} ) {
            $available = undef if ( Cpanel::Easy::Utils::is_redhat() && (Cpanel::Sys::OS::getreleaseversion)[0] < $h->{min_centos} );
        }
    }

    return $available;
}

# Converts a PHP version number to the one "Defined" in EA3.
# This is common when a user has specified an older version
# of PHP in their profile and haven't updated it.
#
# If version can be normalized, it returns the version.
# If version can't, then it returns undef.
#
# NOTE: Defined in EA3 doesn't mean "Available" to user
sub normalize_php_version {
    my $in = shift;
    my $version;

    for my $def ( keys %support_hash ) {
        my $m_in = $in =~ m/^(\d+)_/  ? $1 : '';
        my $m_de = $def =~ m/^(\d+)_/ ? $1 : '';

        if ( $m_in eq $m_de ) {
            $version = $def;
            last;
        }
    }

    return $version;
}

# Retrieves a list of "Available" PHP versions requested in user's profile
#
# NOTE: The set of PHP versions defined in the profile will be <=
# the set of PHP versions available to the user.
sub get_profile_php_versions {
    my $profile_hr = shift;
    my $t          = localtime;
    my @available  = versions();
    my @php;

    for my $ns ( keys %{$profile_hr} ) {
        next unless $profile_hr->{$ns};
        next unless $ns =~ /^Cpanel::Easy::PHP5::(\d+_\d+)/;    # hope we don't make php reverse optmod
        my $tmp = normalize_php_version($1);
        push @php, $tmp if ( $tmp && grep( /^$tmp$/, @available ) );
    }

    return @php;
}

sub is_php_enabled {
    my $profile_hr = shift;
    return ( $profile_hr->{'Cpanel::Easy::PHP5'} ? 1 : 0 );
}

1;
