# Copyright (C) 2015 Google Inc., authors, and contributors <see AUTHORS file>
# Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
# Created By: anze@reciprocitylabs.com
# Maintained By: anze@reciprocitylabs.com

from sqlalchemy.orm import validates

from ggrc import db
from ggrc.models import reflection
from ggrc.models.mixins import BusinessObject
from ggrc.models.mixins import CustomAttributable
from ggrc.models.mixins import FinishedDate
from ggrc.models.mixins import VerifiedDate
from ggrc.models.mixins import TestPlanned
from ggrc.models.mixins import Timeboxed
from ggrc.models.mixins import deferred
from ggrc.models.mixins_assignable import Assignable
from ggrc.models.object_document import Documentable
from ggrc.models.object_owner import Ownable
from ggrc.models.object_person import Personable
from ggrc.models.reflection import PublishOnly
from ggrc.models.relationship import Relatable
from ggrc.models.track_object_state import HasObjectState
from ggrc.models.track_object_state import track_state_for_class


class Assessment(Assignable, HasObjectState, TestPlanned, CustomAttributable,
                 Documentable, Personable, Timeboxed, Ownable,
                 Relatable, FinishedDate, VerifiedDate,
                 BusinessObject, db.Model):
  __tablename__ = 'assessments'

  NOT_DONE_STATES = {u"Open", u"In Progress"}
  DONE_STATES = {u"Finished", u"Verified", u"Final"}
  VALID_STATES = tuple(NOT_DONE_STATES | DONE_STATES)
  ASSIGNEE_TYPES = (u"Creator", u"Assessor", u"Verifier")

  status = deferred(db.Column(db.Enum(*VALID_STATES), nullable=False,
                    default=VALID_STATES[0]), "Assessment")

  design = deferred(db.Column(db.String), "Assessment")
  operationally = deferred(db.Column(db.String), "Assessment")

  object = {}  # we add this for the sake of client side error checking
  audit = {}

  VALID_CONCLUSIONS = frozenset([
      "Effective",
      "Ineffective",
      "Needs improvement",
      "Not Applicable"
  ])

  # REST properties
  _publish_attrs = [
      'design',
      'operationally',
      PublishOnly('audit'),
      PublishOnly('object')
  ]

  _aliases = {
      "audit": {
          "display_name": "Audit",
          "mandatory": True,
      },
      "url": "Assessment URL",
      "design": "Conclusion: Design",
      "operationally": "Conclusion: Operation",
      "related_creators": {
          "display_name": "Creator",
          "mandatory": True,
          "filter_by": "_filter_by_related_creators",
          "type": reflection.AttributeInfo.Type.MAPPING,
      },
      "related_assessors": {
          "display_name": "Assessor",
          "mandatory": True,
          "filter_by": "_filter_by_related_assessors",
          "type": reflection.AttributeInfo.Type.MAPPING,
      },
      "related_verifiers": {
          "display_name": "Verifier",
          "filter_by": "_filter_by_related_verifiers",
          "type": reflection.AttributeInfo.Type.MAPPING,
      },
  }

  def validate_conclusion(self, value):
    return value if value in self.VALID_CONCLUSIONS else ""

  @validates("operationally")
  def validate_opperationally(self, key, value):
    return self.validate_conclusion(value)

  @validates("design")
  def validate_design(self, key, value):
    return self.validate_conclusion(value)

  @classmethod
  def _filter_by_related_creators(cls, predicate):
    return cls._get_relate_filter(predicate, "Creator")

  @classmethod
  def _filter_by_related_assessors(cls, predicate):
    return cls._get_relate_filter(predicate, "Assessor")

  @classmethod
  def _filter_by_related_verifiers(cls, predicate):
    return cls._get_relate_filter(predicate, "Verifier")

track_state_for_class(Assessment)

@@ -326,16 +326,139 @@
 lection%0A
+from ggrc.models.mixins_assignable import Assignable%0Afrom ggrc.models.mixin_autostatuschangable import AutoStatusChangable%0A
 from ggr
@@ -761,61 +761,8 @@
 red%0A
-from ggrc.models.mixins_assignable import Assignable%0A
 from
@@ -1140,16 +1140,37 @@
 essment(
+AutoStatusChangable, 
 Assignab
@@ -1201,16 +1201,33 @@
 Planned,
+%0A                
  CustomA
@@ -1238,33 +1238,16 @@
 butable,
-%0A                
  Documen
@@ -1279,17 +1279,8 @@
 xed,
- Ownable,
 %0A   
@@ -1292,16 +1292,25 @@
         
+ Ownable,
  Relatab
@@ -1424,38 +1424,54 @@
 %0A%0A  
-NOT_DONE
+START
 _STATE
-S
  = %7Bu
-%22
+'
 Open
-%22, u%22
+'%7D%0A  PROGRESS_STATE = %7Bu'
 In P
@@ -1477,17 +1477,17 @@
 Progress
-%22
+'
 %7D%0A  DONE
@@ -1496,23 +1496,22 @@
 TATE
-S
  = %7Bu
-%22
+'
 Finished
 %22, u
@@ -1510,21 +1510,37 @@
 shed
-%22, u%22
+'%7D%0A  END_STATES = %7Bu'
 Verified
 %22, u
@@ -1539,20 +1539,110 @@
 fied
-%22, u%22
+', u'
 Final
-%22%7D
+'%7D%0A%0A  NOT_DONE_STATES = START_STATE %7C PROGRESS_STATE%0A  DONE_STATES = DONE_STATE %7C END_STATES
 %0A  V
@@ -1751,16 +1751,94 @@
 fier%22)%0A%0A
+  FIRST_CLASS_EDIT = START_STATE %7C END_STATES%0A  ASSIGNABLE_EDIT = END_STATES%0A%0A
   status
@@ -2437,16 +2437,288 @@
 ')%0A  %5D%0A%0A
+  _tracked_attrs = %7B%0A      'contact_id',%0A      'description',%0A      'design',%0A      'notes',%0A      'operationally',%0A      'reference_url',%0A      'secondary_contact_id',%0A      'test_plan',%0A      'title',%0A      'url',%0A  %7D%0A  _tracked_date_attrs = %7B'start_date', 'end_date'%7D%0A%0A
   _alias

Use AutoStatusChangable for Assessment