#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  Base class for FHIR resources.
#  2014, SMART Health IT.

from . import fhirabstractbase


class FHIRAbstractResource(fhirabstractbase.FHIRAbstractBase):
    """ Extends the FHIRAbstractBase with server talking capabilities.
    """
    resource_type = 'FHIRAbstractResource'
    
    def __init__(self, jsondict=None, strict=True):
        self._server = None
        """ The server the instance was read from. """
        
        # raise if "resourceType" does not match
        if jsondict is not None and 'resourceType' in jsondict \
            and jsondict['resourceType'] != self.resource_type:
            raise Exception("Attempting to instantiate {} with resource data that defines a resourceType of \"{}\""
                .format(self.__class__, jsondict['resourceType']))
        
        super(FHIRAbstractResource, self).__init__(jsondict=jsondict, strict=strict)
    
    @classmethod
    def _with_json_dict(cls, jsondict):
        """ Overridden to use a factory if called when "resourceType" is
        defined in the JSON but does not match the receiver's resource_type.
        """
        if not isinstance(jsondict, dict):
            raise Exception("Cannot use this method with anything but a JSON dictionary, got {}"
                .format(jsondict))
        
        res_type = jsondict.get('resourceType')
        if res_type and res_type != cls.resource_type:
            return fhirelementfactory.FHIRElementFactory.instantiate(res_type, jsondict)
        return super(FHIRAbstractResource, cls)._with_json_dict(jsondict)
    
    def as_json(self):
        js = super(FHIRAbstractResource, self).as_json()
        js['resourceType'] = self.resource_type
        return js
    
    
    # MARK: Handling Paths
    
    def relativeBase(self):
        return self.__class__.resource_type
    
    def relativePath(self):
        if self.id is None:
            return self.relativeBase()
        return "{}/{}".format(self.relativeBase(), self.id)
    
    
    # MARK: - Server Connection
    
    @property
    def origin_server(self):
        """ Walks the owner hierarchy until it finds an owner with a server.
        """
        server = self._server
        owner = self._owner
        while server is None and owner is not None:
            server = getattr(owner, '_server', None)
            owner = owner._owner
        return server

    @origin_server.setter
    def origin_server(self, server):
        """ Sets the server on an element. """
        self._server = server
    
    @classmethod
    def read(cls, rem_id, server):
        """ Read the resource with the given id from the given server. The
        passed-in server instance must support a `request_json()` method call,
        taking a relative path as first (and only mandatory) argument.
        
        :param str rem_id: The id of the resource on the remote server
        :param FHIRServer server: An instance of a FHIR server or compatible class
        :returns: An instance of the receiving class
        """