<?php

/**
 * @appointment VIN DECODER
 * @author      Alexandr Drozd
*/
 
class VIN {
	
	const continents = [
	  'A-H' => 'Africa',
	  'J-R' => 'Asia',
	  'S-Z' => 'Europe',
	  '1-5' => 'North America',
	  '6-7' => 'Oceania',
	  '8-9' => 'South America'
	], countries = [
	  'AA-AH' => 'South Africa',
	  'AJ-AN' => 'Ivory Coast',
	  'BA-BE' => 'Angola',
	  'BF-BK' => 'Kenya',
	  'BL-BR' => 'Tanzania',
	  'CA-CE' => 'Benin',
	  'CF-CK' => 'Madagascar',
	  'CL-CR' => 'Tunisia',
	  'DA-DE' => 'Egypt',
	  'DF-DK' => 'Morocco',
	  'DL-DR' => 'Zambia',
	  'EA-EE' => 'Ethiopia',
	  'EF-EK' => 'Mozambique',
	  'FA-FE' => 'Ghana',
	  'FF-FK' => 'Nigeria',
	  'JA-J0' => 'Japan',
	  'KA-KE' => 'Sri Lanka',
	  'KF-KK' => 'Israel',
	  'KL-KR' => 'Korea (South)',
	  'KS-K0' => 'Kazakhstan',
	  'LA-L0' => 'China',
	  'MA-ME' => 'India',
	  'MF-MK' => 'Indonesia',
	  'ML-MR' => 'Thailand',
	  'NA-NE' => 'Iran',
	  'NF-NK' => 'Pakistan',
	  'NL-NR' => 'Turkey',
	  'PA-PE' => 'Philippines',
	  'PF-PK' => 'Singapore',
	  'PL-PR' => 'Malaysia',
	  'RA-RE' => 'United Arab Emirates',
	  'RF-RK' => 'Taiwan',
	  'RL-RR' => 'Vietnam',
	  'RS-R0' => 'Saudi Arabia',
	  'SA-SM' => 'United Kingdom',
	  'SN-ST' => 'East Germany',
	  'SU-SZ' => 'Poland',
	  'S1-S4' => 'Latvia',
	  'TA-TH' => 'Switzerland',
	  'TJ-TP' => 'Czech Republic',
	  'TR-TV' => 'Hungary',
	  'TW-T1' => 'Portugal',
	  'UH-UM' => 'Denmark',
	  'UN-UT' => 'Ireland',
	  'UU-UZ' => 'Romania',
	  'U5-U7' => 'Slovakia',
	  'VA-VE' => 'Austria',
	  'VF-VR' => 'France',
	  'VS-VW' => 'Spain',
	  'VX-V2' => 'Serbia',
	  'V3-V5' => 'Croatia',
	  'V6-V0' => 'Estonia',
	  'WA-W0' => 'West Germany',
	  'XA-XE' => 'Bulgaria',
	  'XF-XK' => 'Greece',
	  'XL-XR' => 'Netherlands',
	  'XS-XW' => 'USSR',
	  'XX-X2' => 'Luxembourg',
	  'X3-X0' => 'Russia',
	  'YA-YE' => 'Belgium',
	  'YF-YK' => 'Finland',
	  'YL-YR' => 'Malta',
	  'YS-YW' => 'Sweden',
	  'YX-Y2' => 'Norway',
	  'Y3-Y5' => 'Belarus',
	  'Y0-Y6' => 'Ukraine',
	  'ZA-ZR' => 'Italy',
	  'ZX-Z2' => 'Slovenia',
	  'Z3-Z5' => 'Lithuania',
	  '1A-10' => 'United States',
	  '2A-20' => 'Canada',
	  '3A-37' => 'Mexico',
	  '38-39' => 'Cayman Islands',
	  '4A-40' => 'United States',
	  '5A-50' => 'United States',
	  '6A-6W' => 'Australia',
	  '7A-7E' => 'New Zealand',
	  '8A-8E' => 'Argentina',
	  '8F-8K' => 'Chile',
	  '8L-8R' => 'Ecuador',
	  '8S-8W' => 'Peru',
	  '8X-82' => 'Venezuela',
	  '9A-9E' => 'Brazil',
	  '9F-9K' => 'Colombia',
	  '9L-9R' => 'Paraguay',
	  '9S-9W' => 'Uruguay',
	  '9X-92' => 'Trinidad & Tobago',
	  '93–99' => 'Brazil'
	], makes = [
	  'AAV' => 'Volkswagen',
	  'AFA' => 'Ford',
	  'CL9' => 'Wallyscar',
	  'JA' => 'Isuzu',
	  'JC1' => 'Fiat Automobiles/Mazda',
	  'JF' => 'Fuji Heavy Industries',
	  'JHL' => 'Honda',
	  'JHM' => 'Honda',
	  'JMB' => 'Mitsubishi',
	  'JM6' => 'Mazda',
	  'JN' => 'Nissan',
	  'JS' => 'Suzuki',
	  'JT' => 'Toyota',
	  'JY' => 'Yamaha',
	  'KL' => 'Daewoo/GM Korea',
	  'KMH' => 'Hyundai',
	  'KN' => 'Kia',
	  'WKE' => 'Krone',
	  'KND' => 'Kia',
	  'KPT' => 'SsangYong',
	  'L6T' => 'Geely',
	  'LBE' => 'Beijing Hyundai',
	  'LBV' => 'BMW Brilliance',
	  'LDC' => 'Dongfeng Peugeot-Citroën',
	  'LE4' => 'Beijing Benz',
	  'LFM' => 'LFP (China) FAW Car',
	  'LFV' => 'FAW-Volkswagen',
	  'LGB' => 'Dongfeng Nissan',
	  'LGJ' => 'Dongfeng Fengshen',
	  'LGW' => 'LGX (China) BYD Auto',
	  'LH1' => 'FAW Haima',
	  'LHG' => 'Guangzhou Honda',
	  'LJD' => 'Dongfeng Yueda Kia',
	  'LLV' => 'Lifan',
	  'LMG' => 'GAC Trumpchi',
	  'LPA' => 'LS5 (China) Changan Suzuki',
	  'LSG' => 'SAIC General Motors',
	  'LSJ' => 'SAIC MG',
	  'LSV' => 'SAIC Volkswagen',
	  'LTV' => 'LVG (China) GAC Toyota',
	  'LVH' => 'Dongfeng Honda',
	  'LVR' => 'Changan Mazda',
	  'LVS' => 'Changan Ford',
	  'LVV' => 'Chery',
	  'LWV' => 'GAC Fiat',
	  'LZW' => 'SAIC GM Wuling',
	  'NMT' => 'Toyota',
	  'NM0' => 'Ford Otosan',
	  'PL1' => 'Proton',
	  'SAJ' => 'Jaguar',
	  'SAL' => 'Land Rover',
	  'SAR' => 'Rover',
	  'SAT' => 'Triumph',
	  'SB1' => 'Toyota',
	  'SCC' => 'Lotus Cars',
	  'SCE' => 'DeLorean',
	  'SFD' => 'Alexander Dennis',
	  'SHH' => 'Honda',
	  'SHS' => 'Honda',
	  'SJN' => 'Nissan',
	  'TCC' => 'TMA (Czech Republic) Hyundai',
	  'TMB' => 'Škoda',
	  'TRU' => 'Audi',
	  'TSM' => 'Suzuki',
	  'U5Y' => 'Kia',
	  'UU' => 'Dacia',
	  'VA0' => 'ÖAF',
	  'VF1' => 'Renault',
	  'VF2' => 'Renault',
	  'VF3' => 'Peugeot',
	  'VF4' => 'Talbot',
	  'VF5' => 'Iveco Unic SA',
	  'VF6' => 'Renault Trucks/Volvo',
	  'VF7' => 'Citroën',
	  'VF8' => 'Matra/Talbot/Simca',
	  'VF9' => 'Bugatti',
	  'VFE' => 'IvecoBus',
	  'VNK' => 'Toyota',
	  'VSS' => 'SEAT',
	  'VV9' => 'Tauro Sport Auto',
	  'WAG' => 'Neoplan',
	  'WAU' => 'Audi',
	  'WAP' => 'Alpina',
	  'WBA' => 'BMW',
	  'WBS' => 'BMW M',
	  'WBX' => 'BMW',
	  'WDB' => 'Mercedes-Benz',
	  'WDC' => '(Germany) DaimlerChrysler AG/Daimler AG',
	  'WDD' => '(Germany) DaimlerChrysler AG/Daimler AG',
	  'WMX' => '(Germany) DaimlerChrysler AG/Daimler AG',
	  'WEB' => 'EvoBus',
	  'WF0' => 'Ford of Europe',
	  'WJM' => 'Iveco',
	  'WJR' => 'Irmscher',
	  'WKK' => 'Karl Kässbohrer Fahrzeugwerke',
	  'WMA' => 'MAN',
	  'WME' => 'Smart',
	  'WMW' => 'Mini',
	  'WP0' => 'Porsche car',
	  'WP1' => 'Porsche SUV',
	  'WUA' => 'Quattro',
	  'WVG' => 'Volkswagen',
	  'WVW' => 'Volkswagen',
	  'WV1' => 'Volkswagen Commercial Vehicles',
	  'WV2' => 'Volkswagen Commercial Vehicles',
	  'W0L' => 'Opel/Vauxhall',
	  'W0SV' => 'Opel Special Vehicles',
	  'XLR' => 'DAF Trucks',
	  'YK1' => 'Saab',
	  'YS2' => 'Scania, Södertälje',
	  'YS3' => 'Saab',
	  'YS4' => 'Scania, Katrineholm',
	  'YTN' => 'Saab NEVS',
	  'YV1' => 'Volvo Cars',
	  'YV2' => 'Volvo Trucks',
	  'YV3' => 'Volvo Buses',
	  'ZA9' => 'Bugatti',
	  'ZAM' => 'Maserati',
	  'ZAR' => 'Alfa Romeo',
	  'ZCF' => 'Iveco',
	  'ZFA' => 'Fiat Automobiles',
	  'ZFF' => 'Ferrari',
	  'ZGA' => 'IvecoBus',
	  'ZHW' => 'Lamborghini',
	  'ZLA' => 'Lancia',
	  '1B' => 'Dodge',
	  '1C' => 'Chrysler',
	  '1F' => 'Ford',
	  '1G' => 'General Motors',
	  'KL1' => 'Chevrolet',
	  '1G1' => 'Chevrolet',
	  '1G3' => 'Oldsmobile',
	  '1G9' => 'Google',
	  '1GC' => 'Chevrolet',
	  '1GM' => 'Pontiac',
	  '1HG' => 'Honda',
	  '1J' => 'Jeep',
	  '1L' => 'Lincoln',
	  '1M' => 'Mercury',
	  '1N' => 'Nissan',
	  '1VW' => 'Volkswagen',
	  'JMZ' => 'Mazda',
	  '1YV' => 'Mazda',
	  '2DG' => 'Ontario Drive & Gear',
	  '2F' => 'Ford',
	  '2G' => 'General Motors',
	  '2G1' => 'Chevrolet',
	  '2G2' => 'Pontiac',
	  '2HG' => 'Honda',
	  '2HH' => 'Acura',
	  '2HJ' => 'Honda',
	  '2HK' => 'Honda',
	  '2HM' => 'Hyundai',
	  '2M' => 'Mercury',
	  '2T' => 'Toyota',
	  '3F' => 'Ford',
	  '3G' => 'General Motors',
	  '3HG' => 'Honda',
	  '3HM' => 'Honda',
	  '3N' => 'Nissan',
	  '3VW' => 'Volkswagen',
	  '4F' => 'Mazda',
	  '4J' => 'Mercedes-Benz',
	  '4M' => 'Mercury',
	  '4S3' => 'Subaru',
	  '4S4' => 'Subaru',
	  '4S6' => 'Honda',
	  '4T' => 'Toyota',
	  '4US' => 'BMW',
	  '5FN' => 'Honda',
	  '5J6' => 'Honda',
	  '5L' => 'Lincoln',
	  '5T' => 'Toyota',
	  '5X' => 'Hyundai/Kia',
	  '5YJ' => 'Tesla',
	  '55' => 'Mercedes-Benz',
	  '6F' => 'Ford',
	  '6G' => 'General Motors',
	  '6G1' => 'Chevrolet',
	  'Y6D' => 'Chevrolet',
	  '6G2' => 'Pontiac',
	  '6H' => 'Holden',
	  '6MM' => 'Mitsubishi',
	  '6T1' => 'Toyota',
	  '8AP' => 'Fiat',
	  '8AT' => 'Iveco',
	  '9BD' => 'Fiat Automóveis',
	  '9BW' => 'Volkswagen',
	  '93H' => 'Honda',
	  '93W' => 'Fiat Professional',
	  '93Z' => 'Iveco',
	  '9BH' => 'Hyundai',
	  '9BS' => 'Scania'
	], years = [
	  'A' => 1980,
	  'B' => 1981,
	  'C' => 1982,
	  'D' => 1983,
	  'E' => 1984,
	  'F' => 1985,
	  'G' => 1986,
	  'H' => 1987,
	  'J' => 1988,
	  'K' => 1989,
	  'L' => 1990,
	  'M' => 1991,
	  'N' => 1992,
	  'P' => 1993,
	  'R' => 1994,
	  'S' => 1995,
	  'T' => 1996,
	  'V' => 1997,
	  'W' => 1998,
	  'X' => 1999,
	  'Y' => 2000,
	  '1' => 2001,
	  '2' => 2002,
	  '3' => 2003,
	  '4' => 2004,
	  '5' => 2005,
	  '6' => 2006,
	  '7' => 2007,
	  '8' => 2008,
	  '9' => 2009
	];
	
	protected static function to_int($a){
		return intval(implode('', array_map(function($a){
			$b = intval($a, 36)-10;
			return base_convert(($b < 0 ? $b+36 : $b), 10, 36);
		}, str_split($a))), 36);
	}

	protected static function parse($a, $b){
		return array_reduce(array_keys($a), function($s, $k) use($a, $b){
			$q = array_map(function($a){
				return self::to_int($a);
			}, explode('-', $k));
			return ($b >= $q[0] && $b <= $q[1]) ? $a[$k] : $s;
		});
	}
	
	protected static function get_make($a){
		$max = substr($a, 0, 4);
		$min = substr($max, 0, substr($max, 2, 1) === 9 ? 2 : 3);
		return self::makes[$min] ?: self::makes[$max] ?: $min.' '.$max;
	}

	protected static function get_year($a){
		$val = self::years[substr($a, 9, 1)];
		$inc = strpos('0123456789', substr($a, 6, 1)) !== false ? 0 : 30;
		return $val+$inc;
	}
	
	public static function decode($a){
		$data['continent'] = self::parse(self::continents, self::to_int($a{0}));
		$data['country'] = self::parse(self::countries, self::to_int(substr($a, 0, 2)));
		$data['make'] = self::get_make($a);
		$data['year'] = self::get_year($a);
		return $data;
	}
}
?>