#include<Array.au3>
#include<md5.au3>
#include<WinHTTP.au3>

Global Const $_gsLastFM_APIServer = "ws.audioscrobbler.com"
Global Const $_gsLastFM_APIroot = "/2.0/"
Global Const $_gsLastFM_Auth = "www.last.fm/api/auth/"
Global $_ghLastFM_Client
Global $_gsLastFM_APIkey, $_gsLastFM_Secret, $_gsLastFM_Token

Global $_gasLastFM_Errors[20]
   $_gasLastFM_Errors[0] = "No Error."
   $_gasLastFM_Errors[1] = "There was an error when connecting to the API."
   $_gasLastFM_Errors[8] = "There was an error granting the request token. Please try again later"
   $_gasLastFM_Errors[2] = "Invalid service -This service does not exist"
   $_gasLastFM_Errors[3] = "Invalid Method - No method with that name in this package"
   $_gasLastFM_Errors[4] = "Authentication Failed - You do not have permissions to access the service"
   $_gasLastFM_Errors[5] = "Invalid format - This service doesn't exist in that format"
   $_gasLastFM_Errors[6] = "Invalid parameters - Your request is missing a required parameter"
   $_gasLastFM_Errors[7] = "Invalid resource specified"
   $_gasLastFM_Errors[9] = "Invalid session key - Please re-authenticate"
   $_gasLastFM_Errors[10] = "Invalid API key - You must be granted a valid key by last.fm"
   $_gasLastFM_Errors[11] = "Service Offline - This service is temporarily offline. Try again later."
   $_gasLastFM_Errors[12] = "Subscription Error - The user needs to be subscribed in order to do that"
   $_gasLastFM_Errors[13] = "Invalid method signature supplied"
   $_gasLastFM_Errors[18] = "This user has no free radio plays left. Subscription required."

Func _LastFM_Set_Key($sAPIKey, $sSecret)
	; Author: Prog@ndy
	$_gsLastFM_APIkey = $sAPIKey
	$_gsLastFM_Secret = $sSecret
EndFunc
Func _LastFM_Open($sClientName = "LastFM for AutoItv3 (1.0)", $iProxy = $WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
	; Author: Prog@ndy
	If IsPtr($_ghLastFM_Client) And $_ghLastFM_Client <> 0 Then Return True
	Global $_ghLastFM_Client = _WinHttpOpen($sClientName, $iProxy)
	Return SetError($_ghLastFM_Client=0, 0, $_ghLastFM_Client<>0)
EndFunc
Func _LastFM_Close()
	; Author: Prog@ndy
	If $_ghLastFM_Client = 0 Then Return True
	_WinHTTPCloseHandle($_ghLastFM_Client)
	If @error Then Return SetError(1,0,False)
	Return True
EndFunc

Func _LastFM_Auth_getToken()
	; Author: Prog@ndy
	Local $Ret = _LastFM_Call_API("method=auth.getToken&api_key=" & $_gsLastFM_APIkey)
	Local $Error = _LastFM_Response_getError($Ret)
	If $Error <> 0 Then Return SetError($Error,0,"")
	Return _LastFM_Response_getSimpleValue($Ret,'token')
EndFunc

Func _LastFM_Auth_getSession()
	;auth.getSession
EndFunc

Func _LastFM_Auth_Request($sTitle="LastFM-Login", $sMessage="Bite melden sie sich auf der sich öffnenden Internetseite bei LastFM an und klicken danach auf OK, um diese Anwendung zu nutzen.")
	; Author: Prog@ndy
	ShellExecute($_gsLastFM_Auth & "?api_key=" & $_gsLastFM_APIkey & "&token=" & $_gsLastFM_Token)
	If @error Then Return SetError(1,0,0)
	Return MsgBox(65, $sTitle, $sMessage)=1
EndFunc

Func _LastFM_Generate_Sig($sAPIcall)
	; Author: Prog@ndy
	$sAPIcall = StringSplit($sAPIcall,"&=")
	Local $aAPIcall[$sAPIcall[0]/2][2], $i
	For $i = 1 To $sAPIcall[0] Step 2
		$aAPIcall[($i-1)/2][0] = $sAPIcall[$i]
		$aAPIcall[($i-1)/2][1] = $sAPIcall[$i+1]
	Next
	$sAPIcall=""
	_ArraySort($aAPIcall)
	For $i = 0 To UBound($aAPIcall)-1
		$sAPIcall &= $aAPIcall[$i][0] & $aAPIcall[$i][1]
	Next
	Return _MD5(StringToBinary($sAPIcall & $_gsLastFM_Secret,4))
EndFunc

Func _LastFM_Call_API($sAPIcall, $api_sig=True)
	; Author: Prog@ndy
	If $api_sig Then
		$sig = _LastFM_Generate_Sig(_LastFM_URI_Decode($sAPIcall))
		$sAPIcall &= "&api_sig=" & $sig
	EndIf
	Return _LastFM_Send_Request($sAPIcall)
EndFunc

Func _LastFM_Send_Request($sAPIcall)
	; Author: Prog@ndy
	If Not IsPtr($_ghLastFM_Client) Then Return SetError(2,0,"")
	Local $hConnect = _WinHttpConnect($_ghLastFM_Client, $_gsLastFM_APIServer)
	If $hConnect=0 Then Return SetError(3,0,"")
	Local $hRequest = _WinHttpOpenRequest($hConnect, "GET", $_gsLastFM_APIroot &"?" & $sAPIcall)
	If $hRequest = 0 Then
		_WinHTTPCloseHandle($hConnect)
		Return SetError(4,0,"")
	EndIf
	_WinHTTPSendRequest($hRequest)
	_WinHttpReceiveResponse($hRequest)
	Local $sRecv = Binary("")
	Do
		$sRecv &= _WinHTTPReadData($hRequest,2)
	Until @extended=0
	$sRecv = BinaryToString($sRecv,4)
	_WinHTTPCloseHandle($hRequest)
	_WinHTTPCloseHandle($hConnect)
	Return SetError($sRecv="", 0, $sRecv)
EndFunc

Func _LastFM_Response_getStatus($sResponse)
	; Author: Prog@ndy
	Local $aRet = StringRegExp($sResponse, '<lfm status="(.*?)"',1)
	If @error Then Return SetError(1,0,False)
	If $aRet[0] = 'ok' Then Return True
	Return False
EndFunc

Func _LastFM_Response_getError($sResponse)
	Local $aRet = StringRegExp($sResponse, '<error code="(.*?)"',1)
	If @error Then Return 0
	Return Number($aRet[0])
EndFunc

Func _LastFM_Response_getSimpleValue($sResponse, $sName)
	; Author: Prog@ndy
	Local $aRet = StringRegExp($sResponse, "<" & $sName & ">(.*?)</" & $sName & ">",1)
	If @error Then Return SetError(1,0,"")
	Return $aRet[0]
EndFunc

Func _LastFM_URI_Encode($sData)
	; Author: Prog@ndy
	Local $aData = StringSplit(BinaryToString(StringToBinary($sData,4),1),"")
	Local $nChar
	$sData=""
	For $i = 1 To $aData[0]
		ConsoleWrite($aData[$i] & @CRLF)
		$nChar = Asc($aData[$i])
		Switch $nChar
			Case 45, 46, 48-57, 65 To 90, 95, 97 To 122, 126
				$sData &= $aData[$i]
			Case 32
				$sData &= "+"
			Case Else
				$sData &= "%" & Hex($nChar,2)
		EndSwitch
	Next
	Return $sData
EndFunc

Func _LastFM_URI_Decode($sData)
	; Author: Prog@ndy
	Local $aData = StringSplit(StringReplace($sData,"+"," ",0,1),"%")
	$sData = ""
	For $i = 2 To $aData[0]
		$aData[1] &= Chr(Dec(StringLeft($aData[$i],2))) & StringTrimLeft($aData[$i],2)
	Next
	Return BinaryToString(StringToBinary($aData[1],1),4)
EndFunc
