#! /bin/false

# Copyright (C) 2016-2018 Guido Flohr <guido.flohr@cantanea.com>,
# all rights reserved.

# 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.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

package Qgoda::Repository;
$Qgoda::Repository::VERSION = 'v0.9.3';
use strict;

use Locale::TextDomain qw(qgoda);

use File::Spec;
use File::HomeDir;
use File::Temp;

use Qgoda;
use Qgoda::Util qw(read_file write_file is_archive);

use URI;

sub new {
    my ($class, $uri) = @_;

    $uri = URI->new($uri);

    # This is a mess!  Re-write it from scratch ...
    if ($uri =~ m{^\.\.?\\/}) {
        $uri = 'file://' . File::Spec->rel2abs($uri);
        $uri =~ s{\\}{/}g;
        $uri = URI->new($uri);
    } elsif ($uri =~ s{^~([^/\\]*)}{}) {
        my $user = $1;
        my $home;
        if (length $user) {
            $home = File::HomeDir->user_home($user);
        } else {
            $home = File::HomeDir->my_home;
        }
        $uri = 'file://' . $home . '/' . $uri;
        $uri =~ s{\\}{/}g;
        $uri = URI->new($uri);
    } elsif (File::Spec->file_name_is_absolute($uri)) {
        $uri = URI->new('file://' . $uri);
    }

    if (undef eq $uri->scheme) {
        my $file = "$uri";

        if (File::Spec->file_name_is_absolute($file)) {
            $uri = URI->new($file, 'file');
        } else {
            if ($file =~ /^[_a-zA-Z][_a-zA-Z0-9]*\@/) {
                # Replace the first colon with a slash.
                $uri =~ s{:}{/};
                $uri = URI->new('git+ssh://' . $uri);
            } elsif (!-e $file && $file =~ m{/}) {
                $uri = URI->new('git://github.com/' . $file);
            } else {
                $uri = URI::file->new_abs($file);
            }
        }
    }

    my $self = {
        __uri => $uri
    };

    my $protocol = $uri->scheme;
    my %known = (
        'git' => 'Git',
        'git+ssh' => 'Git',
        'git+http' => 'Git',
        'git+https' => 'Git',
        'git+file' => 'Git',
        'file' => 'File'
    );

    $self->{__type} = $known{$protocol} || 'LWP';

    if ('Git' eq $self->{__type}) {
        my $scheme = $self->{__uri}->scheme;
        if ($scheme =~ /\+(.*)/) {
            $self->{__uri}->scheme($1);
        }
    }

    # If an http/https URI does not look like an archive, assume that it is
    # also a git URI.
    if ('http' eq $uri->scheme || 'https' eq $uri->scheme) {
        # These are file name extenders likely to contain an archive.
        if (!is_archive $uri->path) {
            $self->{__type} = 'Git';
            $self->{__source} = 'Github'
                if 'github.com' eq $self->{__uri}->host;
        }
    }

    if ($self->{__type}) {
        if ('Git' eq $self->{__type}) {
            if ('github.com' eq $self->{__uri}->host) {
                $self->{__source} = 'Github';
            }
        }
    }

    bless $self, $class;
}

sub type { shift->{__type} }
sub source { shift->{__source} }
sub uri { shift->{__uri} }

sub fetch {
    my ($self) = @_;

    my $logger = Qgoda->new->logger;

    my $fetcher_class = 'Qgoda::Repository::Fetcher::' . $self->{__type};
    my $fetcher_module = $fetcher_class;
    $fetcher_module =~ s{::}{/}g;
    $fetcher_module .= '.pm';
    require $fetcher_module;

    $logger->info(__x("fetching '{uri}'", uri => $self->{__uri}));

    my $tmp = File::Temp->newdir;
    $logger->debug(__x("created temporary directory '{dir}'",
                       dir => $tmp));

    my $fetcher = $fetcher_class->new;
    my $dir = $fetcher->fetch($self->{__uri}, $tmp->dirname);

    # Return the object as well, so that it doesn't go out of scope here.
    return ($dir, $tmp);
}

package URI::git;
$URI::git::VERSION = 'v0.9.3';
use strict;

use base qw(URI::http);

package URI::git_Phttp;
$URI::git_Phttp::VERSION = 'v0.9.3';
use strict;

use base qw(URI::git);

package URI::git_Phttps;
$URI::git_Phttps::VERSION = 'v0.9.3';
use strict;

use base qw(URI::git);

package URI::git_Pssh;
$URI::git_Pssh::VERSION = 'v0.9.3';
use strict;

use base qw(URI::git);

package URI::git_Pfile;
$URI::git_Pfile::VERSION = 'v0.9.3';
use strict;

use base qw(URI::file);

1;