#-*- coding:utf-8 -*-

#Copyright (c) 2012, Bartłomiej Nitoń
#All rights reserved.

#Redistribution and use in source and binary forms, with or without modification, are permitted provided 
#that the following conditions are met:

#    Redistributions of source code must retain the above copyright notice, this list of conditions and 
#    the following disclaimer.
#    Redistributions in binary form must reproduce the above copyright notice, this list of conditions 
#    and the following disclaimer in the documentation and/or other materials provided with the distribution.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE.

from django.db.models import *
from django.contrib.auth.models import User

class Configuration(Model):
    name = CharField(max_length=16, primary_key=True, unique=True, db_column='nazwa_konfiguracji')
    
    example_approvers_num = PositiveIntegerField(db_column='liczba_zatwierdzajacych')
    selected_conf = BooleanField(db_column='wybrana_konfiguracja', default=False)
    
    def __unicode__(self):
        return '%s' % self.name             

    class Meta:
        db_table = 'konfiguracje_narzedzia'
        ordering = ['name']
        permissions = (
          ('manage_tool_configuration', u'Może zmieniać konfigurację narzędzia.'),
        )

class VocabularyFormat(Model):
    format = CharField(max_length=64, primary_key=True, unique=True, db_column='format_slownika')
    
    def __unicode__(self):
      return '%s' % self.format 
   
class Vocabulary(Model):
    name = CharField(max_length=64, primary_key=True, unique=True, db_column='slownik') 
    managers = ManyToManyField(User, blank=True,
                             related_name='managed_vocabularies')
    editors = ManyToManyField(User, blank=True,
                            related_name='editable_vocabularies')
    viewers = ManyToManyField(User, blank=True,
                            related_name='visible_vocabularies')
    
    def __unicode__(self):
        return '%s' % self.name             

    class Meta:
        db_table = 'slowniki'
        ordering = ['name']
        permissions = (
          ('manage_vocabulary', u'Może zarządzać słownikami'),
        )

def visible_vocabularies(user):
  if user.has_perm('dictionary.view_all_lemmas'):
    return Vocabulary.objects.all()
  else:
    return user.visible_vocabularies.all()

# tabela z nazwami statusów haseł
class Lemma_Status(Model):
    status = CharField(max_length=16, db_column='status', verbose_name=u'status')
    # okresla czy po zmianie na wskazany status trzeba walidowac ramki
    validate = BooleanField(db_column='czy_walidowac', default=False) 
    # okresla czy po zmianie na wskazany status trzeba sprawdzac czy potwierdzono przyklady wlasne
    check_examples = BooleanField(db_column='sprawdzic_przyklady', default=False) 
    # okresla kolejnosc prezentowania statusow
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    def __unicode__(self):
        return '%s' % (self.status) 
    
    class Meta:
      db_table = 'statusy_hasel'
      ordering = ['priority']
      permissions = (
        ('confirm_lemma', u'Może zaznaczać hasła jako sprawdzone.'),
        ('see_stats', u'Może oglądać swoje statystyki.'),
        ('see_all_stats', u'Może oglądać statystyki wszystkich.'),
      )

class Lemma(Model):
    id = AutoField(primary_key=True, db_column='l_id')
    # czasownik w bezokoliczniku
    entry = CharField(max_length=64, db_column='haslo', db_index=True,
                      verbose_name=u'hasło')
    # wlasciciel hasla
    owner = ForeignKey(User, blank=True, null=True, db_column='wlasciciel',
                       related_name='lemmas')
    # slownik do ktorego nalezy
    vocabulary = ForeignKey(
                       Vocabulary, db_column='slownik', 
                       related_name='lemmas')
    # status obrobki hasla
    status = ForeignKey(Lemma_Status, db_column='status', 
                       related_name='lemmas')
    locker = ForeignKey(User, blank=True, null=True, db_column='osoba_zapisujaca',
                       related_name='locked_lemmas')
    # klasy zgodnosci stare ramki
    compatibility_classes = ManyToManyField("CompatibilityClass", db_table='klasy_zgodnosci',
                                           blank=True, null=True, related_name='lemmas')
    # dawne wersje hasla
    old_versions = ManyToManyField('Change', db_table='haslo_stareWersje',
                                   blank=True, null=True, related_name='lemmas')
    # czy haslo jest aktualne czy nie (pomocne w systemie kontroli zmian)
    old = BooleanField(db_column='nieaktualny') 
    #nowe ramki
    frames = ManyToManyField('Frame', db_table='haslo_ramki', blank=True, null=True,
                             related_name='lemmas')
    #stare ramki
    old_frames = ManyToManyField('Old_Frame', db_table='haslo_stareRamki',
                                 blank=True, null=True, related_name='lemmas')
    # przyklady z NKJP dla ramek hasla
    nkjp_examples = ManyToManyField('NKJP_Example', db_table='haslo_ramkiNkjp',
                                    blank=True, null=True, related_name='lemmas')
    # przyklady z Dendrarium dla ramek hasla - chwilowy brak implementacji
    dendr_examples = ManyToManyField('Dendrarium_Example', db_table='haslo_ramkiDendrarium',
                                     blank=True, null=True, related_name='lemmas')
    # oceny ramek dla ramek hasla
    frame_opinions = ManyToManyField('Frame_Opinion', db_table='lemma_ramkiOpinie',
                                     blank=True, null=True, related_name='lemmas')
    # przyklady przyporzadkowane do hasla jako calosci (pola frame i atributes beda niewypelniane)
    lemma_nkjp_examples = ManyToManyField('NKJP_Example', db_table='haslo_Nkjp',
                                    blank=True, null=True, related_name='lemmasSelf')
    
    def __unicode__(self):
      return '%s (%s)' % (self.entry, self.vocabulary)

    class Meta:
      db_table = 'hasla'
      permissions = (
        ('view_lemma', u'Może oglądać leksemy'), 
        ('change_all_lemmas', u'Może zmieniać wszystkie hasła'),
        ('change_lemmas', u'Może zmieniać hasła, których jest właścicielem'),
      )

class CompatibilityClass(Model):
    compatibility = PositiveIntegerField(db_column='procent_kompatybilnosci')
    comp_lemmas = ManyToManyField("Lemma", db_table='komatybilnosc_hasla',
                    blank=True, null=True, related_name='compatibilityClasses')
    
    def __unicode__(self):
      return str(self.compatibility)+'%'


class Frame_Opinion(Model):
    frame = ForeignKey('Frame', db_column='ramka', related_name='opinions',
                       blank=True, null=True)
    value = ForeignKey('Frame_Opinion_Value', db_column='opinia', related_name='opinions')
    
    def __unicode__(self):
      return '%s (%s)' % (self.frame.text_rep, self.value.value)

class Frame_Opinion_Value(Model):
    value = CharField(max_length=16, db_column='wartosc', 
                         verbose_name=u'wartosc', unique=True)
    # okresla kolejnosc prezentowania opinii
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    def __unicode__(self):
      return '%s' % (self.value)


class Frame(Model):
    id = AutoField(primary_key=True, db_column='f_id')
    # pozycje skladniowe
    positions = ManyToManyField('Position', db_table='ramka_pozycje', 
                                blank=True, null=True, related_name='frames')
    # charakterystyki ramy
    characteristics = ManyToManyField('Frame_Characteristic', db_table='cechy_ramy',
                                      blank=True, null=True, related_name='frames')  
    # reprezentacja tekstowa
    text_rep = TextField(db_column='tekst_rep', verbose_name=u'reprezentacja tekstowa', unique=True)
    
    def __unicode__(self):
      return '%s' % (self.text_rep)

class NKJP_Example(Model):
    # ramka ktorej dotyczy przyklad
    frame = ForeignKey(Frame, db_column='ramka', related_name='nkjp_examples',
                       blank=True, null=True)
    # argumenty ramki, ktorych dotyczy przyklad
    arguments = ManyToManyField('NKJP_ArgSelection', db_table='przykladNKJP_argumenty',
                                blank=True, null=True, related_name='nkjp_examples')
    # przykladowe zdanie
    sentence = TextField(db_column='zdanie', verbose_name=u'zdanie')
    # zrodlo
    source = ForeignKey('NKJP_Source', db_column='zrodlo', related_name='nkjp_examples')
    # komentarz do przykladu
    comment = TextField(db_column='komentarz', verbose_name=u'komentarz')
    # ocena przykladu
    opinion = ForeignKey('NKJP_Opinion', db_column='opinia', related_name='nkjp_examples')
    # osoby ktore zatwierdzily haslo
    approvers = ManyToManyField(User, db_table='osoby_zatwierdzajace',
                                blank=True, null=True, related_name='nkjp_examples')
    # if the example was approved by two users
    approved = BooleanField(db_column='zatwierdzony', default=True)
    
    def __unicode__(self):
      return '%s' % (self.sentence)
  
    class Meta:
      db_table = 'nkjp_przyklad'
      permissions = (
        ('confirm_example', u'Może potwierdzać przykłady.'),
      )
      
class NKJP_ArgSelection(Model):
    # pozycja na ktorej wystepuja zaznaczone argumenty
    position = ForeignKey('Position', db_column='pozycja', related_name='nkjp_argSelections',
                          blank=True, null=True)
    # zaznaczone argumenty
    arguments = ManyToManyField('Argument', db_table='wyborArgNKJP_argumenty',
                                blank=True, null=True, related_name='nkjp_argSelections')
    
    def __unicode__(self):
      return '%s' % (self.position.text_rep)
    
      
class NKJP_Source(Model):
    source = CharField(max_length=64, db_column='zrodlo', 
                         verbose_name=u'zrodlo', unique=True)
    # flaga oznaczajaca czy dane zrodlo wymaga dodatkowego komentarza
    comment_required = BooleanField(db_column='wymagany_komentarz', default=False)
    # flaga oznaczajaca czy przyklad pochodzacy z dango zrodla powinien zostac potwierdzony
    confirmation_required = BooleanField(db_column='wymagane_potwierdzenie', default=False)
    # okresla kolejnosc prezentowania zrodel przykladu
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    class Meta:
      ordering = ['priority']
    
    def __unicode__(self):
      return '%s' % (self.source)
  
class NKJP_Opinion(Model):
    opinion = CharField(max_length=16, db_column='opinia', 
                         verbose_name=u'opinia', unique=True)
    # okresla kolejnosc prezentowania opinii o przykladzie na liscie rozwijanej
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    class Meta:
      ordering = ['priority']
    
    def __unicode__(self):
      return '%s' % (self.opinion)

# dokonczyc przy opracowywaniu interfejsu do dendrarium
class Dendrarium_Example(Model):
    # przykladowe zdanie
    sentence = TextField(db_column='zdanie', verbose_name=u'zdanie')
    
    def __unicode__(self):
      return '%s' % (self.sentence)
      
class Position(Model):
    # kategoria pozycji
    categories = ManyToManyField('PositionCategory', db_table='pozycja_kategorie', null=True, blank=True,
                             related_name='positions')
    # argumenty pozycji
    arguments = ManyToManyField('Argument', db_table='pozycja_argumenty',
                                blank=True, null=True, related_name='positions')
    # reprezentacja tekstowa                                                 # UWAGA, TUTAJ swieze, wywalono unique
    text_rep = TextField(db_column='tekst_rep', verbose_name=u'reprezentacja tekstowa')#, unique=True)
    
    def __unicode__(self):
      return '%s' % (self.text_rep)
    
    class Meta:
      db_table = 'pozycje_skladniowe'
      
class PositionCategory(Model):
    category = CharField(max_length=16, db_column='kategoria', 
                         verbose_name=u'typ', unique=True)
    # czy kategoria jest zwiazana z kontrola
    control = BooleanField(db_column='kontrola')
    #priorytet prezentowania danych
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    def __unicode__(self):
        return '%s' % (self.category)
    
class Argument(Model):
    type = CharField(max_length=16, db_column='typ_argumentu', 
                         verbose_name=u'typ argumentu')
    atributes = ManyToManyField('Atribute', db_table='argument_atrybuty', 
                                null=True, blank=True, related_name='arguments')
    # reprezentacja tekstowa
    text_rep = TextField(db_column='tekst_rep', verbose_name=u'reprezentacja tekstowa', unique=True)
    realizations = ManyToManyField('Argument', db_table='realizacje', # Tutaj, nowe
                              related_name='arguments', null=True, blank=True)
    
    class Meta:
      permissions = (
        ('create_realization', u'Może kreować realizacje argumentów.'),
      )
    
    def __unicode__(self):
        return '%s' % (self.text_rep)
    
    
class Argument_Model(Model):
    # nazwa typu argumentu
    arg_model_name = CharField(max_length=16, db_column='nazwa_modelu', 
                         verbose_name=u'nazwa modelu', primary_key=True, unique=True)
    # mozliwe wartosci przyjmowane przez atrybut o nazwie model_name
    atribute_models = ManyToManyField('Atribute_Model', db_table='wzory_atrybutow',
                                      related_name='argument_models', 
                                      blank=True, null=True) # to pole jednak nie jest wymagane, patrz refl, epsilon
        # czy wystepuje tylko jako realizacja xp, lp, comprepnp
    realization_only = BooleanField(db_column='tylko_realizacja', default=False) # Tutaj, nowe
    has_realizations = BooleanField(db_column='posiada_realizacje', default=False) # Tutaj, nowe
    
    # priorytet prezentowania argumentow w pozycji
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    def __unicode__(self):
      return '%s' % (self.arg_model_name)
  
class Atribute_Model(Model):
    # nazwa typu atrybutu
    atr_model_name = CharField(max_length=32, db_column='nazwa_atrybutu', 
                         verbose_name=u'nazwa modelu atrybutu')
    # mozliwe wartosci przyjmowane przez atrybut o nazwie model_name
    atribute_values = ManyToManyField('Atribute_Value', db_table='wartosci_atrybutow', 
                                null=True, blank=True, related_name='atribute_models')
    # true jesli typ atrybutu jest wartoscia tekstowa
    text_atribute = BooleanField(db_column='tekstowy')
    # priorytet prezentowania atrybutow w argumencie
    priority = PositiveIntegerField(db_column='priorytet', primary_key=True)
    
    def __unicode__(self):
      return '%s' % (self.atr_model_name)

# Mozliwe wartosci atrybutow
class Atribute_Value(Model):
    value = CharField(max_length=32, db_column='wartosc_atrybutu', 
                         verbose_name=u'wartość atrybutu')    
    # wartosc dostepna tylko w argumentach bedacych realizacjami
    realization_only = BooleanField(db_column='tylko_realizacja', default=False) # Tutaj, nowe
    # priorytet waznosci atrybutow
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    def __unicode__(self):
      return '%s' % (self.value)
  
  
class Atribute(Model):
    # wzor/typ atrybutu
    type = CharField(max_length=16, db_column='typ_atrybutu', 
                         verbose_name=u'typ atrybutu')
    # zaznaczane jesli atrybut nie jest typu tekstowego
    atribute_value = ForeignKey(Atribute_Value, db_column='wartosc_atrybutu',
                                    null=True, blank=True, verbose_name=u'wartość atrybutu',
                                    related_name='atributes') 
     
    def __unicode__(self):
      return '%s' % (self.atribute_value.value)
     
class Old_Frame(Model):
    # tekst starej ramki zgodnie ze starym slownikiem
    old_frame_value = CharField(max_length=64, db_column='tekst_ramki', 
                         verbose_name=u'tekst ramki') 
    property = ForeignKey('Old_Frame_Property', db_column='wlasciwosc',
                          related_name='old_frames')
    # czy pochodzi od hasla w formie zwrotnej
    reflex = BooleanField(db_column='zwrotna')
    
    def __unicode__(self):
      return '%s' % (self.old_frame_value)
  
class Old_Frame_Property(Model):
    name = CharField(max_length=16, db_column='nazwa', 
                         verbose_name=u'nazwa', unique=True)
    value = CharField(max_length=16, db_column='pelna_nazwa', 
                         verbose_name=u'pelna_nazwa')
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    def __unicode__(self):
      return '%s' % (self.name)
    
class Frame_Characteristic(Model):
    # wzor/typ charakterystyki ramki
    type = CharField(max_length=16, db_column='typ_char', 
                         verbose_name=u'typ charakterystyki')
    # wartosc cechy ramki
    value = ForeignKey('Frame_Char_Value', db_column='wartosc_cechy_ramki',
                          related_name='frame_characteristic')
    
    def __unicode__(self):
      return '%s' % (self.value.value)
    
class Frame_Char_Model(Model):
    # nazwa typu modelu argumentu
    model_name = CharField(max_length=16, db_column='nazwa_modelu', 
                         verbose_name=u'nazwa modelu', primary_key=True, unique=True)
    # mozliwe wartosci przyjmowane przez dany model charakterystyki ramki
    frame_char_values = ManyToManyField('Frame_Char_Value', db_table='model_wartosciCechRamy',
                                        related_name='frame_char_models')
    # priorytet prezentowania kolejnych klas cech w ramce
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    def __unicode__(self):
      return '%s' % (self.model_name)
    
class Frame_Char_Value(Model):
    value = CharField(max_length=32, db_column='wartosc', 
                         verbose_name=u'wartość cechy ramki', blank=True, null=True)
    # priorytet
    priority = PositiveIntegerField(db_column='priorytet', blank=True, null=True)
    
    def __unicode__(self):
      return '%s' % (self.value)
    
class Message(Model):
    # tytul wiadomosci
    topic = TextField(db_column='tytul', verbose_name=u'tytuł')
    # tekst wiadomosci
    message_text = TextField(db_column='wiadomosc', verbose_name=u'wiadomość')
    # uzytkownik pozostawiajacy wiadomosc
    sender = ForeignKey( User, db_column='uzytkownik', related_name='messages')
    # haslo dla ktorego pozostawiono wiadomosc
    lemma = ForeignKey(Lemma, db_column='postac_hasla', related_name='messages',
                       blank=True, null=True)    
    #data nadania wiadomosci
    time = DateTimeField(auto_now_add=True, db_column='data_nadania') # tutaj, zmieniono z auto_now na auto_now_add
    # czy wiadomosc jest prywatna
    private = BooleanField(db_column='prywatna', default=False)
    # czy wiadomosc jeszcze nie byla czytana
    new = BooleanField(db_column='nowa', default=True) # Tutaj, nowe pole, aby oznaczac nowe notatki
    
    class Meta:
      db_table = 'wiadomosci'
      permissions = (
        ('add_notes', u'Może dodawać wiadomości'),
        ('view_notes', u'Może przeglądać swoje notatki')
      )
    
    def __unicode__(self):
      return '%s' % (self.message_text)

class Change(Model):
    # uzytkownik ktory dokonal zmiany
    user = ForeignKey( User, db_column='modyfikujacy', related_name='changes')
    # data modyfikacji
    time = DateTimeField(auto_now_add=True, db_column='data_modyfikacji')
    # stara wersja hasla
    entry = ForeignKey(Lemma, db_column='postac_hasla', related_name='changes',
                       blank=True, null=True)
    # wlasciciel hasla w czasie modyfikacji
    act_owner = ForeignKey(User, db_column='aktualny_wlasciciel', related_name='changesOwn',
                            blank=True, null=True)
    
    def __unicode__(self):
      return '%s data: %s' % (self.entry.entry, self.time)
