from ldt.ldt_utils.models import Project, Content, Segment
from django.db.models import F, Q
from piston.handler import BaseHandler
from piston.utils import rc, require_extended
from ldt.ldt_utils.utils import LdtAnnotation
from ldt.ldt_utils.stat import add_annotation_to_stat
from ldt.security import protect_models, unprotect_models
from ldt.ldt_utils.segmentserializer import SegmentSerializer
import logging #@UnresolvedImport


class ProjectHandler(BaseHandler):
    allowed_methods = ('GET', 'PUT',)
    model = Project   

    def read(self, request, project_id):
        """
        returns a single project
        """
        return Project.objects.get(ldt_id=project_id)
    
    @require_extended
    def update(self, request, project_id):
        #return rc.ALL_OK
        logging.debug("request " + repr(request))
        data = request.data
        ldt_str = data["ldt"]
        
        logging.debug("request data" + repr(ldt_str))
        
        if not ldt_str:
            return rc.BAD_REQUEST
        
        project = Project.objects.get(ldt_id=project_id)
        
        project.ldt = ldt_str
        
        unprotect_models()
        project.save()
        protect_models()
    
        return rc.ALL_OK


class AnnotationHandler(BaseHandler):
    allowed_methods = ('PUT',)
    model = Project
    
    
    @require_extended
    def update(self, request, project_id):
        """
        This method is called when a PUT request is sent to http://<plateform_location>/api/ldt/projects/<project_id>.<format>. 
            <project_id> is the ldt_id field of the project. If <projet_id> does not match any project on the platform, a 410 ("Gone")
            error will be returned.
            <format> is the format of the data sent back by the server. It can be 'json', 'yaml', 'xml' or 'pickle'.
            
        If the request contains a content-type header whose value is set to "application/json" and a valid utf-8 encoded JSON file,
        the following conditions will be checked before the annotations are added : 
            If the submitted file is not valid or refers to a media that is not contained in the project, a 500  ("Bad Request")
            error will be returned. If the "type" field of an annotation matches an already existing cutting, it will be added to that 
            cutting. Otherwise, a new cutting will be added (as well as a new ensemble if needed). New cuttings are added to the view 
            "View at the last recording" if it exists, or to the view "Init view" else. If none of those views exist, the server will 
            not add the cutting to a view. Several annotations can be added at the same time if the submitted file contains multiple 
            annotations. The server returns the file submitted if all annotations have been added successfully, and adds to this file
            IDs of created annotations to the file with a 200("OK") error code.
        
        If no content-type header is set, the file submitted must be a valid XML file and will replace entirely the ldt field
        of the project without any verifications.  
        
        Example :
        
        Remark : The file below contain the minimum necessary fields and attributes for the handler to work. If one field or attribute is
        missing (e.g. author, or date) during submission, an error will occur.
        
        A platform is reachable at http://localhost/. It contains a project with ID a0593b58-f258-11df-80e1-00145ea4a2be. This project has
        a content milosforman_amadeus, which has a cutting Salieri inside the view "View at the last recording". The following JSON file exists in the current directory :
    
        Example of ajax call with 2 differents annotations :
        $('#mon_ajax').click(function(e) {
            var url = "{% url project_api project_id='c8448f21-272d-11e1-876b-c8bcc896c290' emitter_format='.json' %}"; // Don't forget the "." before "json" !
            
            var monjson = '{\
                    "annotations": [\
                        {\
                            "type": "c_07BA1284-5F24-71A8-1EE2-423EED999B8A",\
                            "type_title": "New cutting name if necessary",\
                            "media": "briandepalma_scarfacedepalma",\
                            "begin": 1600000,\
                            "end": 2100000,\
                            "content": {\
                                "data": "new scar annot"\
                            },\
                            "tags": [ "json","dude" ]\
                        }\
                    ],\
                    "meta": {\
                        "creator": "John Doe",\
                        "created": "2011-09-10T09:12:58"\
                    }\
                }';
            var monjson2 = '{\
                    "annotations": [\
                        {\
                            "type": "c_07BA1284-5F24-71A8-1EE2-423EED999B8A",\
                            "type_title": "New cutting name if necessary",\
                            "media": "briandepalma_scarfacedepalma",\
                            "begin": 2400000,\
                            "end": 3000000,\
                            "content": {\
                                "data": "ntm iam 2"\
                            },\
                            "tags": [ "jak" ]\
                        }\
                    ],\
                    "meta": {\
                        "creator": "John Doe",\
                        "created": "2011-09-10T09:12:58"\
                    }\
                }';
            
            $.ajax({
                url: url,
                type: 'PUT',
                contentType: 'application/json',
                data: monjson,
                // bug with jquery >= 1.5, "json" adds a callback so we don't specify dataType
                //dataType: 'json',
                success: function(json, textStatus, XMLHttpRequest) {
                    alert("success = " + json);
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    alert("ERROR = " + jqXHR.responseText + ", " + errorThrown);
                }
            });
        });
        
        If we send a PUT request with curl :    
        $curl -X PUT http://localhost/api/ldt/projects/a0593b58-f258-11df-80e1-00145ea4a2be.json -d @example.JSON -H  "content-type:application/json"
        A new cutting titled "New cutting name" will be created with the first annotation inside, and the annotation "Annotation about Salieri"
        will be added to the Salieri cutting. The returned file is :
        
        {
            "annotations": [
                {
                    "id": "6d8baf01-ffb1-11e0-810c-001485352c9a",
                    "type": "id_annot_type",
                    "type_title": "New cutting name",
                    "media": "milosforman_amadeus",
                    "begin": 50000,
                    "end": 900000,
                    "content": {
                        "data": "new annotation"
                    },
                    "tags": [ "json" ]
                },
                {
                    "id": "6d8baf00-ffb1-11e0-8097-001485352c9b",
                    "type": "another_id_annot_type",
                    "type_title": "Salieri",
                    "media": "milosforman_amadeus",
                    "begin": 700000,
                    "end": 1200000,
                    "content": {
                        "data": "Annotation about Salieri"
                    },
                    "tags": [ "xml", "test", "blop" ]
                }
            ],
            
            "meta": {
                "creator": "John Doe",
                "created": "2011-09-10T09:12:58"
            }
        }
        
        """
        #return rc.ALL_OK
        try:
            project = Project.objects.get(ldt_id=project_id)
        except Project.DoesNotExist:
            return rc.NOT_HERE
    
        adder = LdtAnnotation(project)
        logging.debug("request json " + repr(request.data))
        
        unprotect_models() # Allows anonymous user to modify models in this request only 

        meta = request.data['meta']
        author = meta['creator']
        date = meta['created']
        new_annotations = request.data['annotations']

        for a in new_annotations:
            dur = str(a['end'] - a['begin'])
            begin = str(a['begin'])
            type_id, new_id = adder.add(a['media'], a['type'], a['type_title'], a['content']['data'], '', a['tags'], begin, dur, author, date)
            if not new_id:
                protect_models()
                return rc.BAD_REQUEST
            
                            
            content = project.contents.get(iri_id=a['media'])
            add_annotation_to_stat(content, a['begin'], a['end'])
            
            # We update the ids
            a['type'] = type_id
            a['id'] = new_id
        
        # We save if there were added annotation
        if len(new_annotations)>0 :
            adder.save()
        
        protect_models()
        
        return request.data
            

        
class ContentHandler(BaseHandler):
    allowed_methods = ('GET', )
    model = Content
    exclude = (
               ("media_obj"),
               )   

    def read(self, request, iri_id):
        """
        returns a single content
        """
        return Content.objects.get(iri_id=iri_id)
    

class SegmentHandler(BaseHandler):
    allowed_methods = ('GET', )
    model = Segment
    exclude = (
               ("project_obj"),
               ("content"),
               )
    
    def read(self, request, iri_id, begin, end):
        """
        returns segments about content iri_id between timecodes begin and end
        """
        begin = int(begin)
        end = int(end)
        
        content = Content.objects.filter(iri_id=iri_id)
        if not content:
            return rc.NOT_FOUND
        content = content[0]
        
        segments = Segment.objects.filter(content=content).filter(
                    Q(start_ts__gt=begin, start_ts__lt=end) |                            # segment starts between begin and end
                    Q(start_ts__gt=begin-F('duration'), start_ts__lt=end-F('duration')) |# segment ends between begin and end
                    Q(start_ts__lt=begin, start_ts__gt=end-F('duration'))                # period [begin:end] is included in the segment
                    )
        
        a = SegmentSerializer(content, segments)
        return a.serialize_to_cinelab()
    
