#pylint: disable=C0103,no-member
"""
Models
"""
from flask import Blueprint
from app import constants

model_blueprint = Blueprint('models', __name__)

from app import app
from flask import json
from flask.json import JSONEncoder as old_json

from google.appengine.ext import ndb

class JSONEncoder(old_json):
    """
    Wrapper class to try calling an object's to_dict() method. This allows
    us to JSONify objects coming from the ORM. Also handles dates & datetimes.
    """

    def default(self, obj): #pylint: disable=E0202
        if isinstance(obj, ndb.Key):
            return obj.id()
        try:
            return obj.to_dict()
        except AttributeError:
            return json.JSONEncoder.default(self, obj)

app.json_encoder = JSONEncoder

class Base(ndb.Model):
    """
    Add some default properties and methods to the SQLAlchemy declarative Base.
    """
    @classmethod
    def from_dict(cls, values):
        """
        Creates an instance from the given values
        """
        inst = cls()
        inst.populate(**values)
        return inst

    def to_dict(self):
        result = super(Base, self).to_dict()
        if self.key:
            result['key'] = self.key.id() # Add the key as a string
        return result

class Submission(Base): #pylint: disable=R0903
    """
    The Submission Model
    """
    location = ndb.StringProperty()

class User(Base): #pylint: disable=R0903
    """
    The User Model
    """
    email = ndb.StringProperty()
    login = ndb.StringProperty()
    role = ndb.StringProperty(default=constants.STUDENT_ROLE)
    first_name = ndb.StringProperty()
    last_name = ndb.StringProperty()
    submissions = ndb.StructuredProperty(Submission, repeated=True)

    def __repr__(self):
        return '<User %r>' % self.email

class Assignment(Base): #pylint: disable=R0903
    """
    The Assignment Model
    """
    name = ndb.StringProperty()
    points = ndb.IntegerProperty()
    submissions = ndb.StructuredProperty(Submission, repeated=True)


@@ -14,14 +14,8 @@
 ble=
-C0103,
 no-m
@@ -27,16 +27,15 @@
 %0A%22%22%22
-%0A
 Models
-%0A
+.
 %22%22%22%0A
@@ -262,19 +262,57 @@
  import 
-n
 db
+,ndb%0A%0ABadValueError = db.BadValueError%0A
 %0A%0Aclass 
@@ -786,16 +786,17 @@
 ncoder%0A%0A
+%0A
 class Ba
@@ -821,97 +821,30 @@
  %22%22%22
-%0A    Add some default properties and methods to the SQLAlchemy declarative Base.%0A    
+Shared utilities.
 %22%22%22%0A
+%0A
     
@@ -899,25 +899,16 @@
      %22%22%22
-%0A        
 Creates 
@@ -940,25 +940,17 @@
 n values
-%0A        
+.
 %22%22%22%0A    
@@ -1203,274 +1203,193 @@
 lt%0A%0A
+%0A
 class 
-Submission(Base): #pylint: disable=R0903%0A    %22%22%22%0A    The Submission Model%0A    %22%22%22%0A    location = ndb.StringProperty()%0A%0Aclass User(Base): #pylint: disable=R0903%0A    %22%22%22%0A    The User Model%0A    %22%22%22%0A    email = ndb.StringProperty()%0A    login = ndb.StringProperty()
+User(Base):%0A    %22%22%22Users.%22%22%22%0A    email = ndb.StringProperty() # Must be associated with some OAuth login.%0A    login = ndb.StringProperty() # TODO(denero) Legacy of glookup system
 %0A   
@@ -1525,76 +1525,8 @@
 ty()
-%0A    submissions = ndb.StructuredProperty(Submission, repeated=True)
 %0A%0A  
@@ -1588,16 +1588,17 @@
 .email%0A%0A
+%0A
 class As
@@ -1616,31 +1616,8 @@
 se):
- #pylint: disable=R0903
 %0A   
@@ -1689,109 +1689,1145 @@
 ty()
-%0A    points = ndb.IntegerProperty()%0A    submissions = ndb.StructuredProperty(Submission, repeate
+ # Must be unique to support submission.%0A    # TODO(denero) Validate uniqueness of name.%0A    points = ndb.FloatProperty()%0A    creator = ndb.StructuredProperty(User)%0A%0A%0Adef validate_contents(contents):%0A    %22%22%22Contents is a JSON string encoding a map from protocols to data.%22%22%22%0A    if not contents:%0A        raise BadValueError('Empty contents')%0A    try:%0A        files = json.loads(contents)%0A        if not isinstance(files, dict):%0A            raise BadValueError('Contents is not a JSON map')%0A        for k in files:%0A            if not isinstance(k, (str, unicode)):%0A                raise BadValueError('key %25r is not a string' %25 k)%0A        # TODO(denero) Check that each key corresponds to a known protocol,%0A        #              and call protocol-specific validators on each value.%0A    except Exception as e:%0A        raise BadValueError(e)%0A%0A%0Aclass Submission(Base):%0A    %22%22%22A submission is generated each time a student runs the client.%22%22%22%0A    submitter = ndb.UserProperty()%0A    assignment = ndb.StructuredProperty(Assignment)%0A    contents = ndb.StringProperty(validator=validate_contents)%0A    date = ndb.DateTimeProperty(auto_now_ad
 d=True)%0A
 %0A
@@ -2825,9 +2825,8 @@
 d=True)%0A
-%0A

Rewrite model to put assignment/user info into submission records.