from django.db import models
from django.contrib.contenttypes.models import ContentType
from app.models import ItfModel
from django.contrib.contenttypes import generic


'''
Classes that need to link to a ContentType should link to ModelExtra instead. Maybe there's a better way to do this?
'''
class ModelExtra(models.Model):
  model = models.OneToOneField(ContentType)
  friendly_name = models.CharField(max_length=255, blank=True, null=True)
  friendly_name_plural = models.CharField(max_length=255, blank=True, null=True)
  sort_options = models.ManyToManyField("ModelSort", blank=True, null=True)
  has_comments = models.BooleanField(default=False)
    

  def __unicode__(self):
    return "%d: %s" % (self.id, self.friendly_name)  

  def get_dict(self):
    return {
      'id': self.id,
      'module': self.model.model_class()._meta.app_label,
      'model': self.model.model_class().__name__,
      'has_comments': self.has_comments, 
#      'info': self.info,
      'friendly_name': self.friendly_name,
      'friendly_name_plural': self.friendly_name_plural,
      'fk_filters': self.model.model_class().fk_filters,
      'fts_fields': self.model.model_class().fts_fields,
      'sort_options': map(lambda x: {'key': x.key, 'operator': x.operator, 'text': x.text}, self.sort_options.all())
    }



class ModelSort(models.Model):
  operator = models.CharField(max_length=4)
  key = models.CharField(max_length=64)
  text = models.CharField(max_length=256)

  def __unicode__(self):
    return "%s%s: %s" % (self.operator, self.key, self.text,)



"""
Base class for buttons - buttons can be an 'extra_button' for either a Box class or an instance of a model (defined in ModelExtra). 
"""
class Button(ItfModel):
  typ = ''
  icon = models.CharField(max_length=255) #FIXME: read choices from list of icons
  mouseover = models.CharField(max_length=255)

  class Meta:
    abstract = True

  def __unicode__(self):
    return "%d: %s" % (self.id, self.mouseover)

  def get_dict(self):
    data = self.get_data()
    data['id'] = self.id,
    data['type'] = self.typ,
    data['icon'] = self.icon,
    data['mouseover'] = self.mouseover
    return data

  '''
  Subclasses need to implement get_data and return additional data-items as a dict. Keys cannot be one of 'type', 'icon', and 'mouseover' in the return value.
  '''
  def get_data(self):
    return {}


class BoxButton(Button):
  class Meta:
    abstract = True

class ModelButton(Button):
  class Meta:
    abstract = True


class DialogButton(BoxButton):
  typ = 'dialog'
  dialogTitle = models.CharField(max_length=255)
  dialogHTML = models.TextField()

  def get_data(self):
    return {
      'title': self.dialogTitle,
      'html': self.dialogHTML
    }


class StaticDownloadButton(BoxButton):
  typ = 'staticDownload'
  fil = models.FileField(upload_to='uploads/button_downloads/')

  def get_data(self):
    return {
      'file': {
        'path': self.fil.url
      }
    }


class ModelDownloadButton(ModelButton):
  typ = 'modelDownload'
  file_field = models.CharField(max_length=100) #name of field which holds the file/s(?) to be downloaded

  def get_data(self):
    return {
      'file': {
        'path': self.fil.url
      }
    }



"""
Join model to enable m2m relations to generic foreign keys
"""
class ExtraButton(models.Model):
  related_name = models.CharField(max_length=255, blank=True, null=True)
  button_content_type = models.ForeignKey(ContentType)
  button_id = models.PositiveIntegerField()
  button = generic.GenericForeignKey('button_content_type', 'button_id')  

  def __unicode__(self):
    return "%d: %s" % (self.id, self.related_name)

  def get_dict(self):
    return self.button.get_dict()

"""
Join model
"""
class PanelBoxes(models.Model):
  related_name = models.CharField(max_length=255, blank=True, null=True)
  box_content_type = models.ForeignKey(ContentType)
  box_id = models.PositiveIntegerField()
  box = generic.GenericForeignKey("box_content_type", "box_id")

  def __unicode__(self):
    return "%d: %s" % (self.id, self.related_name)

  def get_dict(self):
    return self.box.get_dict()

  class Meta:
    verbose_name = "Panel box"
    verbose_name_plural = "Panel boxes"



'''
Abstract base-class for boxes.
'''
class Box(ItfModel):
  title = models.CharField(max_length=256)
  extra_buttons = models.ManyToManyField("ExtraButton", blank=True, null=True)  
  logo = models.ImageField(upload_to="upload/box_logos/", blank=True, null=True)

  class Meta:
    abstract = True

  def render():
    return ''

  def __unicode__(self):
    return "%d: %s" % (self.id, self.title)

  def _get_buttons(self):
    ret = []
    for b in self.extra_buttons.all():
      ret.append(b.button.get_dict())
    return ret  

  def get_dict(self):
    return {}


class StaticBox(Box):
  html = models.TextField(blank=True, null=True)  

  def get_dict(self):
    return {
      'id': self.id,
      'type': 'StaticBox',
      'title': self.title,
      'html': self.html,
      'extra_buttons': self._get_buttons()
    }


class ModelsBox(Box):
  default_model = models.ForeignKey(ModelExtra)
  view_models = models.ManyToManyField(ModelExtra, related_name="box_views", blank=True, null=True)
  info = models.TextField(blank=True)

  @property
  def module(self):
    return self.default_model.app_label

  def get_dict(self):
    data = {
      'id': self.id,
      'type': 'ModelsBox',
      'title': self.title,
      'info': self.info,
      'extra_buttons': self._get_buttons(),
      'default_model': self.default_model.get_dict(),
      'view_models': map(lambda x: x.get_dict(), self.view_models.all())
    }  
    return data



class Panel(models.Model):
  title = models.CharField(max_length=255)
  boxes = models.ManyToManyField("PanelBoxes", blank=True, null=True)
  enabled = models.BooleanField(default=False)
  displayed = models.BooleanField(default=False)

  def __unicode__(self):
    return self.title

  def get_dict(self):
    return {
      'id': self.id,
      'title': self.title,
      'boxes': map(lambda x: x.get_dict(), self.boxes.all())
    }

'''
class Page(models.Model):
  class Meta:
    abstract = True
'''
