#!/usr/bin/perl -w
#
# HU.pm
#
# Version 0.3 - Fixed BAMOSZ website scraping and download stocks
# directly from www.BET.hu
# This version based on ZA.pm module
#
# Zoltan Levardy <zoltan at levardy dot org> 2008, 2009
# Kristof Marussy <kris7topher at gmail dot com> 2014

package Finance::Quote::HU;

use strict;

use constant DEBUG => $ENV{DEBUG};
use if DEBUG, 'Smart::Comments';

use LWP::UserAgent;
use HTTP::Request::Common;
use HTML::TableExtract;
use Encode;
use JSON;
use Web::Scraper;

our $VERSION = '1.52'; # VERSION

my $BAMOSZ_MAINURL = "http://www.bamosz.hu/";
my $BAMOSZ_URL = $BAMOSZ_MAINURL . "alapoldal?isin=";

my $BSE_MAINURL = "http://www.bet.hu/";
my $BSE_URL = $BSE_MAINURL . '/oldalak/ceg_adatlap/$security/';

sub methods {
    return ( hufund  => \&bamosz,
             bamosz  => \&bamosz,
             hustock => \&bse,
             bse     => \&bse,
             bet     => \&bse,
             hu      => \&hu,
             hungary => \&hu
    );
}

sub labels {
    my @fundlabels =
        qw/symbol method source name currency isin date isodate price last/;
    my @stocklabels =
        qw/symbol method source currency isin date isodate price open close
           high low p_change last/;
    my @alllabels = ( @stocklabels, "name" );
    return ( hufund  => \@fundlabels,
             bamosz  => \@fundlabels,
             hustock => \@stocklabels,
             bse     => \@stocklabels,
             bet     => \@stocklabels,
             hu      => \@alllabels,
             hungary => \@alllabels
    );
}

sub hu {
    my $quoter  = shift;
    my @symbols = @_;
    my %info;

    for my $symbol (@symbols) {
        my %bse_info = bse( $quoter, $symbol );
        if ( $bse_info{ $symbol, "success" } ) {
            %info = ( %info, %bse_info );
            next;
        }

        my %bamosz_info = bamosz( $quoter, $symbol );
        if ( $bamosz_info{ $symbol, "success" } ) {
            %info = ( %info, %bamosz_info );
            next;
        }

        $info{ $symbol, "success" }  = 0;
        $info{ $symbol, "errormsg" } = "Fetch from bse or bamosz failed";
    }

    return wantarray() ? %info : \%info;
}

sub bse {
  my $quoter  = shift;
  my @symbols = @_;
  my %info;

  my $ua = $quoter->user_agent;

  for my $symbol (@symbols) {
    eval {
      my $url      = $BSE_URL . $symbol;
      my $response = $ua->request(GET $url);

      ### bse response : $response->content

      die "Request error" unless $response->is_success;
      die "Failed to find JSON data" unless $response->content =~ m|window[.]dataSourceResults=([{].+[}])</script>|;

      my $json = decode_json $1;

      ### json : $json

      ### keys : keys %{$json}
      my @profile_key = grep {/CompanyProfileDataSource;table=left/} keys %{$json};
      die "Failed to process JSON" unless @profile_key == 1;

      my $profile = $json->{$profile_key[0]};

      ### profile : $profile

      foreach my $term (@{$profile}) {
        $info{$symbol, "close"} = hu_decimal($term->{value}) if $term->{title} eq "El\x{151}z\x{151} z\x{e1}r\x{f3}\x{e1}r";
        $info{$symbol, "high"}  = hu_decimal($term->{value}) if $term->{title} eq "Napi maximum"; 
        $info{$symbol, "low"}   = hu_decimal($term->{value}) if $term->{title} eq "Napi minimum"; 
      }

      my @trade_key = grep {/CompanyProfileDataSource;table=trades/} keys %{$json};
      die "Failed to process JSON" unless @trade_key == 1;

      my $trade = $json->{$trade_key[0]};

      $info{$symbol, "last"} = hu_decimal($trade->[0]->{price});

      my $processor = scraper {
        process '//*[@id="cp_tab_content_2"]/div[3]/div[3]/table/tbody/tr[1]/td[2]/span', 'ticker'   => 'TEXT';
        process '//*[@id="cp_tab_content_2"]/div[3]/div[3]/table/tbody/tr[2]/td[2]/span', 'isin'     => 'TEXT';
        process '//*[@id="cp_tab_content_2"]/div[3]/div[3]/table/tbody/tr[4]/td[2]/span', 'currency' => 'TEXT';
        process '//*[@id="cp_tab_content_2"]/div[1]/div/div/div[2]/div/div[2]/span[2]', 'date'       => 'TEXT';
      };

      my $data = $processor->scrape($response);

      ### data : $data

      $info{ $symbol, "symbol" }   = $data->{ticker};
      $info{ $symbol, "isin" }     = $data->{isin};
      $info{ $symbol, "currency" } = $data->{currency};
      
      $quoter->store_date(\%info, $symbol, {isodate => $data->{date}});

      $info{ $symbol, "method" }  = "bse";
      $info{ $symbol, "source" }  = $BSE_MAINURL;
      $info{ $symbol, "success" } = 1;
    };

    if ($@) {
      ### bse error : $@
      $info{ $symbol, "method"}   = "bse";
      $info{ $symbol, "errormsg"} = $@;
      $info{ $symbol, "success"}  = 0;
    }
  }

  return wantarray() ? %info : \%info;
}

sub bamosz {
    my $quoter  = shift;
    my @symbols = @_;
    my %info;

    my $ua = $quoter->user_agent;

    for my $symbol (@symbols) {
        $info{ $symbol, "method" }  = "bamosz";
        $info{ $symbol, "source" }  = $BAMOSZ_MAINURL;
        $info{ $symbol, "success" } = 0;

        my $url      = $BAMOSZ_URL . $symbol;
        my $response = $ua->request( GET $url);

        ### bamosz response : $response

        unless ( $response->is_success ) {
            $info{ $symbol, "errormsg" } = "Request error";
            next;
        }

        my $te = HTML::TableExtract->new( attribs => { class => "dataTable" } );
        $te->parse( decode_utf8( $response->content ) );
        unless ( $te->first_table_found ) {
            $info{ $symbol, "errormsg" } = "No dataTable found";
            next;
        }

        my $ts = $te->table( 0, 0 );
        $info{ $symbol, "name" } = $ts->cell( 0, 1 );
        my $isin = $ts->cell( 2, 1 );
        $info{ $symbol, "symbol" }   = $isin;
        $info{ $symbol, "isin" }     = $isin;
        $info{ $symbol, "currency" } = $ts->cell( 3, 1 );
        my $price = hu_decimal( $ts->cell( 5, 1 ) );
        $info{ $symbol, "price" } = $price;
        $info{ $symbol, "last" }  = $price;
        my $date = $ts->cell( 6, 1 );
        $quoter->store_date( \%info, $symbol, { isodate => $date } );

        $info{ $symbol, "success" } = 1;
    }

    return wantarray() ? %info : \%info;
}

sub trim {
    my $s = shift;
    if ($s) {
        $s =~ s/^\s+//;
        $s =~ s/\s+$//;
        return $s;
    }
    else {
        return '';
    }
}

sub hu_decimal {
    my $s = shift;
    if ($s) {
        $s =~ s/[^\d,-]//g;
        $s =~ s/,/./;
        return $s;
    }
    else {
        return '';
    }
}

1;

=head1 NAME

Finance::Quote::HU - Obtain Hungarian Securities from www.bet.hu
and www.bamosz.hu

=head1 SYNOPSIS

    use Finance::Quote;
    $q = Finance::Quote->new;
    # Don't know anything about failover yet...

=head1 DESCRIPTION

This module obtains information about Hungarian Securities. Share fetched from
www.bet.hu, while mutual funds retrieved from www.bamosz.hu. Stocks are
searched by ticker while mutual funds may only searched by ISIN.

=head1 LABELS RETURNED

Information available may include the following labels:

method source name symbol currency date last price low high open close
p_change

=head1 SEE ALSO

Budapest Stock Exchange (BET) website - http://www.bet.hu
BAMOSZ website - http://www.bamosz.hu/

Finance::Quote

=cut
