<?php

namespace elanpl\L3;

class Serialization{
    protected $serializers; //registered serializers dictionary

    public function __construct()
    {
        $this->serializers = array(); 
    }

    public function register($contentType, $serializer, $viewModelClass = null){
        
        if(!class_exists($serializer,true)){
            throw new \Exception("Class \"$serializer\" not found!");
        }

        if(!isset(class_implements($serializer, true)['elanpl\\L3\\ISerializer'])){
            throw new \Exception("Class \"$serializer\" does not implement ISerializer interface!");
        }

        if(isset($viewModelClass) && $viewModelClass!=''){
            $class_key = $viewModelClass.'|';
        }
        else{
            $class_key = '';
        }
        $this->serializers[$class_key.$contentType] = $serializer;
    }

    public function match($acceptTypes, $viewModel=null){
        if(isset($viewModel)){
            if(is_object($viewModel)){
                $viewModelClass = get_class($viewModel);
            }
            if(is_string($viewModel)){
                $viewModelClass = $viewModel;
            }
        }

        if(is_array($acceptTypes)){
            $registeredTypes = array_keys($this->serializers);

            foreach ($acceptTypes as $type){
                //Dedicated config for ViewModel class first...
                if(array_key_exists($viewModelClass."|".$type, $this->serializers)){
                    return $type;
                }
                foreach($registeredTypes as $rtype_with_class){
                    $rtype_parts = explode("|", $rtype_with_class);
                    if(count($rtype_parts)==2){
                        $rclass = $rtype_parts[0];
                        $t = explode("/", $type);
                        $rt = explode("/", $rtype_parts[1]);
                        if($rclass==$viewModelClass && ($t[0]=="*" || $rt[0]=="*" || $t[0]==$rt[0]) && ($t[1]=="*" || $rt[1]=="*" || $t[1]==$rt[1])){
                            return $rtype_with_class;
                        }
                    }
                }

                //Then check configs without the ViewModel class name
                if(array_key_exists($type, $this->serializers)){
                    return $type;
                }
                foreach($registeredTypes as $rtype){
                    $t = explode("/", $type);
                    $rt = explode("/", $rtype);
                    if(($t[0]=="*" || $rt[0]=="*" || $t[0]==$t[0]) && ($t[1]=="*" || $rt[1]=="*" || $t[1]==$t[1])){
                        return $rtype;
                    }
                }
            }
        }
        return false;
    }

    public function serialize($contentType, $viewModel){
        if(isset($this->serializers[get_class($viewModel).'|'.$contentType])){
            $serializerClass = $this->serializers[get_class($viewModel).'|'.$contentType];
        }
        else if(isset($this->serializers[$contentType])){
            $serializerClass = $this->serializers[$contentType];
        }

        if(isset($serializerClass)){
            $serializer = new $serializerClass();
            return $serializer->serialize($viewModel);
        }
        else{
            return null;
        }
    }
}