<?php

namespace AuthStack\Driver\SOAP\BPS\Lib;

use AuthStack\Driver\SOAP\BPS\Exception\InvalidResponse;
use AuthStack\Driver\SOAP\BPS\Lib\Response\AuthenticateResponse;
use AuthStack\Driver\SOAP\BPS\Lib\Response\LogoutResponse;
use AuthStack\Driver\SOAP\BPS\Lib\Response\UserDetailsResponse;

class XMLParser
{
    /**
     * @param string $xmlString
     * @throws InvalidResponse
     * @return AuthenticateResponse
     */
    public function authenticate( $xmlString )
    {
        $xml = simplexml_load_string( $xmlString );

        if ( $xml->authentication->count() == 0 )
        {
            throw new InvalidResponse('Missing node: "authentication"');
        }

        $object = new AuthenticateResponse();

        $object->version = (string)$xml->version;
        $object->dataset = (string)$xml->dataset;
        $object->authentication = strtolower((string)$xml->authentication );

        switch ( $object->authentication )
        {
            case 'ok':
                $attr = $xml->authentication->attributes();
                $object->_auth_status       = AuthStatus::STATUS_OK;
                $object->authenticationCode = (string)$attr['code'];
                $object->bpsId              = (string)$attr['bpsID'];

                $attr = $xml->account->attributes();
                $object->authenticated      = (string)$attr['authenticated'];
                $object->token              = (string)$xml->token;
                break;
            case 'fail':
                $object->fail = (string)$xml->fail;
                $object->_auth_status = AuthStatus::fromString( $object->fail );

                $attr = $xml->authentication->attributes();
                $object->authenticationCode = (string)$attr['code'];
                $object->bpsId              = '';

                $attr = $xml->account->attributes();
                $object->authenticated      = (string)$attr['authenticated'];
                $object->token              = '';
                break;
            default:
                $object->_auth_status = AuthStatus::STATUS_UNKNOWN;
                break;
        }

        return $object;
    }

    /**
     * @param $xmlString
     * @return LogoutResponse
     * @throws InvalidResponse
     */
    public function logout( $xmlString )
    {
        $xml = simplexml_load_string( $xmlString );

        if ( $xml->result->count() == 0 )
        {
            throw new InvalidResponse('Missing node: "result"');
        }

        $object = new LogoutResponse();
        $object->version = (string)$xml->version;
        $object->dataset = (string)$xml->dataset;
        $object->bpsId   = (string)$xml->bpsid;
        $object->result  = (string)$xml->result;

        return $object;
    }

    /**
     * @param string $xmlString
     * @return UserDetailsResponse
     * @throws InvalidResponse
     */
    public function getUserDetails( $xmlString )
    {
        $xml = simplexml_load_string( $xmlString );

        if ( $xml->accounts->count() == 0 )
        {
            throw new InvalidResponse('Missing node: "accounts"');
        }

        if ( $xml->accounts->account->count() == 0 )
        {
            throw new InvalidResponse('Missing node: "accounts->account"');
        }

        if ( $xml->accounts->account->count() > 1 )
        {
            throw new InvalidResponse('Invalid response, got more than one account node');
        }

        $array = json_decode(json_encode($xml->accounts->account), true);
        $this->cleanup( $array, true );

        unset( $array['codes'] );

        foreach ($xml->accounts->account->codes as $arrCodes )
        {
            /**
             * @var $arrCodes \SimpleXMLElement|\stdClass
             */
            $attr = $arrCodes->attributes();
            $type = (string)$attr['type'];
            $array['codes'][$type] = [];
            foreach ( $arrCodes->code as $code )
            {
                $array['codes'][$type][] = (string)$code;
            }
        }

        $attr = $xml->accounts->account->attributes();

        $object = new UserDetailsResponse();
        $object->bpsId  = (string)$attr['bpsId'];
        $object->locked = (string)$attr['locked'];
        $object->attributes = $array;

        return $object;
    }

    /**
     * Recursively iterates through an array and cleans up values ( trims )
     * @param array $array
     * @param bool $emptyArrayIsNull
     */
    protected function cleanup( array &$array, $emptyArrayIsNull = false )
    {
        foreach ($array as &$item )
        {
            if ( is_array( $item ) )
            {
                if ( empty($item) && $emptyArrayIsNull )
                {
                    $item = null;
                }
                else
                {
                    $this->cleanup( $item, $emptyArrayIsNull );
                }
            }
            else
            {
                $item = trim($item);
            }
        }
    }
}