#!/usr/bin/perl

use strict;
use warnings;
use Compress::Zlib;
use LWP::UserAgent;

my $uuid = '3d32b20481b1df262ada6899540c8701';

my $uri = 'http://mobile.maps.yandex.net/printer?uuid='.$uuid.'&protocol_ver=2&lang=ru-RU&';

# yandex_mobile_main(1238, 642, 11); 

sub ym_add_field_to_request
{
  my $req = shift;
  my $field_name = shift;
  my $field_value = shift;  
  my $msg = HTTP::Message->new(['Content-Disposition' => 'form-data; name="'.$field_name.'"']);
  $msg->add_content($field_value);
  $req->add_part($msg);
}

sub ym_add_content_to_request
{
  my $req = shift;
  my $field_name = shift;
  my $field_content_type = shift;  
  my $field_content = shift;
  my $msg = HTTP::Message->new(
    [
      'Content-Disposition' => 'form-data; name="'.$field_name.'"', 
      'Content-Type' => $field_content_type
    ]
  );
  $msg->add_content($field_content);
  $req->add_part($msg);
}

sub ym_get_boundary
{
  my $boundary = '--------------';
  my @rand = ('0'..'9');    
  for (0..25){$boundary .= $rand[rand(@rand)];}
  return $boundary;
}

sub mycrc32 
{
  my ($input, $init_value, $polynomial) = @_;

  $init_value = 0 unless (defined $init_value);
  $polynomial = 0xedb88320 unless (defined $polynomial);

  my @lookup_table;

  for (my $i=0; $i<256; $i++) {
    my $x = $i;
    for (my $j=0; $j<8; $j++) {
      if ($x & 1) {
        $x = ($x >> 1) ^ $polynomial;
      } else {
        $x = $x >> 1;
      }
    }
    push @lookup_table, $x;
  }

  my $crc = $init_value ^ 0xffffffff;

  foreach my $x (unpack ('C*', $input)) {
    $crc = (($crc >> 8) & 0xffffff) ^ $lookup_table[ ($crc ^ $x) & 0xff ];
  }

  $crc = $crc ^ 0xffffffff;

  return $crc;
}

sub ym_get_crc
{
  my $src_str = shift;
  my $key_str = shift;
  
  my @data = unpack("C*", $src_str);
  my @key = unpack("C*", $key_str); 
  
  my $data_size = @data;
  my $key_size = @key;
  
  for (my ($i) = 0; $i < $data_size; $i++) {
    $data[$i] ^= $key[$i % $key_size];       
  }    
  
  return mycrc32(pack("C*", @data));
}

sub yandex_mobile_main
{
  my $x = shift;
  my $y = shift;
  my $z = shift; 
  
  $z--;
  
  my $tiles_xml = '<?xml version="1.0" \?><tiles><tile x="'.$x.'" y="'.$y.'" zoom="'.$z.'" layer="map" size="1" /></tiles>';  
  my $tiles_gzip = Compress::Zlib::memGzip($tiles_xml);
  my $packet_id = ym_get_crc($tiles_gzip, $uuid);
    
  my $request = HTTP::Request->new('POST', $uri);  
  $request->protocol('HTTP/1.0');  
  $request->header('Content-Type' => 'multipart/form-data; boundary='.ym_get_boundary);
  $request->header('User-Agent' => 'YandexMaps/1003 CFNetwork/609.1.4 Darwin/13.0.0');
  $request->header('Accept' => '*/*');  
  $request->header('Accept-Encoding' => 'gzip');
  $request->header('Accept-Language' => 'ru');
  $request->header('Lang' => 'ru-RU');
  $request->header('Connection' => 'Close');    
  
  ym_add_field_to_request($request, 'scalefactor', '2');  
  ym_add_field_to_request($request, 'protocol_ver', '2');    
  ym_add_field_to_request($request, 'gzip', '1');
  ym_add_field_to_request($request, 'packetid', $packet_id);
  ym_add_field_to_request($request, 'uuid', $uuid);
  ym_add_content_to_request($request, 'tiles', 'application/gzip', $tiles_gzip);
  
  my $ua = new LWP::UserAgent;
  my $response = $ua->request($request); 
  
  if ($response->is_success) 
  {
    my @data = unpack("C*", $response->content);
    my @ytld = splice(@data, 0, 0x34); # skip 52 bytes -> ToDo: check YTLD content
    
    my $img_size = @data;
    my $img = pack("C*", @data);
    
    my $content_type = 'image/png';
    my $old_content_type = ($response->content_type);    
    my $old_size = ($response->content_length);
                     
    my $http_header = ($response->headers_as_string);    
    $http_header =~ s/$old_content_type/$content_type/i;
    $http_header =~ s/$old_size/$img_size/i;
    
    # print $http_header;
    # open(my $fh, '>', "ym.png") or die $!;
    # binmode($fh);
    # print $fh ($img);
    # close($fh);
    
    my @ret = ();
    push @ret, ($response->code); # http result code
    push @ret, ($img_size); # content size
    push @ret, ($content_type); # content type
    push @ret, ($http_header); # headers
    push @ret, ($img); # body
    return \@ret;
  }
  else 
  {    
    return ($response->code);
  }  
}