# -*- coding: UTF-8 -*-
from __future__ import unicode_literals

from numbers import Number

from django.utils import timezone
import datetime
import os

from django.contrib.gis.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from django.utils.text import slugify
from django.utils.dateformat import format

def _timestamp(dt):
    return int(format(dt, 'U'))

def _temp_conv(temp, unit):
    if (not (isinstance(unit, str) or isinstance(unit, unicode))) or \
            not isinstance(temp, Number):
        return None

    if unit != _('Celsius') and unit != _('Fahrenheit'):
        raise ValueError(_('Invalid unit'))

    if unit == _('Celsius'):
        return temp * 9 / 5 + 32

    return temp

class SiteManager(models.Manager):
    """
    Manager for the site class - creates a site to be used in tests
    """
    default = 'POINT(-121.3846841 44.0612385)'

    def create_site(self, site_name, location=default,
                    description='', image=None, active=True):

        site = self.create(site_name=site_name, location=location,
                           description=description, image=image, active=active)
        return site

def validate_Site_location(location):
    if location.x > 180 or location.x < -180:
        raise ValidationError(_('Longitude is not within valid range.'))
    if location.y > 90 or location.y < -90:
        raise ValidationError(_('Latitude is not within valid range.'))

@python_2_unicode_compatible
class Site(models.Model):
    """
    The Sites model holds the information of a site, including the geographic
    location as a pair of latitudinal/longitudinal coordinates and an optional
    text description of entry.
    """

    site_name = models.CharField(max_length=250, verbose_name=_('site name'))
    description = models.TextField(blank=True,
                                   verbose_name=_('site description'))
    site_slug = models.SlugField(unique=True, max_length=50, editable=False)

    # Geo Django fields to store a point
    location = models.PointField(default='POINT(-121.3846841 44.0612385)',
                                 verbose_name=_('location'),
                                 validators=[validate_Site_location])
    image = models.ImageField(null=True, blank=True, verbose_name=_('image'),
                              upload_to='site_photos/')
    active = models.BooleanField(default=True)

    created = models.DateTimeField(default=timezone.now)
    modified = models.DateTimeField(default=timezone.now)

    objects = models.Manager()  # default manager
    test_objects = SiteManager()  # custom manager for use in writing tests

    def __str__(self):
        return self.site_name

    def to_dict(self):
        return {
            'site_name': self.site_name,
            'site_slug': self.site_slug,
            'description': self.description,
            'location': {
                'x': self.location.x,
                'y': self.location.y
            },
            'created': _timestamp(self.created),
            'modified': _timestamp(self.modified)
        }

    def save(self, **kwargs):
        'Ensure site_slug is a unique, not-null field'
        if not self.site_slug:
            self.site_slug = origSlug = slugify(self.site_name)[:50]
            # If the generated slug is not unique, append a number
            for i in xrange(1, 99):
                if not Site.objects.filter(site_slug=self.site_slug).exists():
                    break
                # Ensure the slug is never longer than it's field's maxiumum
                self.site_slug = "%s%d" % (origSlug[:50-len(str(i))], i)
        super(Site, self).save()

class SchoolManager(models.Manager):
    """
    Manager for the school class - creates a school to be used in tests
    """
    def create_school(self, name, school_type='Test', address='12345 Foo St',
                      city='Bar', province='Baz', zipcode='54321',
                      active=True):

        school = self.create(name=name, school_type=school_type,
                             address=address, city=city, province=province,
                             zipcode=zipcode, active=active)
        return school

@python_2_unicode_compatible
class School(models.Model):
    OPTIONS = (
            ('Elementary School', _('Elementary School')),
            ('Middle School', _('Middle School')),
            ('High School', _('High School')),
            ('Organization', _('Organization')),
            ('Community College', _('Community College')),
            ('State College', _('State College')),
            )

    name = models.CharField(max_length=250)
    school_type = models.CharField(
        max_length=250, choices=OPTIONS, default=0, null=True,
        verbose_name=_('school type'))
    address = models.CharField(max_length=250)
    city = models.CharField(max_length=250)
    province = models.CharField(max_length=250)
    zipcode = models.CharField(max_length=250)
    active = models.BooleanField(default=False)

    created = models.DateTimeField(default=timezone.now)
    modified = models.DateTimeField(default=timezone.now)

    # nid and assoc_uid are only used by the data_scripts to make relations
    # between the models
    # nid = models.PositiveIntegerField(blank=True, null=True)
    # assoc_uid = models.PositiveIntegerField(blank=True, null=True)

    test_objects = SchoolManager()
    objects = models.Manager()

    def __str__(self):
        return self.name

@python_2_unicode_compatible
class SchoolRelations(models.Model):
    uid = models.PositiveIntegerField(blank=True, null=True)
    school = models.ForeignKey(
        School, null=True, on_delete=models.CASCADE,
        limit_choices_to={'active': True}
    )

    objects = models.Manager()

    def __str__(self):
        return self.school.name

def validate_UserProfile_birthdate(birthdate):
    today = datetime.datetime.now()
    if birthdate.year > today.year - 13:
        raise ValidationError(_('You must be at least 13'))
    elif birthdate.year == today.year - 13:
        if birthdate.month > today.month:
            raise ValidationError(_('You must be at least 13'))
        elif birthdate.month == today.month:
            if birthdate.day > today.day:
                raise ValidationError(_('You must be at least 13'))

class GalleryAlbum(models.Model):
    title = models.CharField(max_length=250,
                             verbose_name=_('title'))
    description = models.TextField(blank=True, verbose_name=_('description'))

    site = models.ForeignKey(
        Site, null=True, on_delete=models.CASCADE,
        verbose_name=_('Stream/Site name'), limit_choices_to={'active': True}
    )
    school = models.ForeignKey(
        School, null=True, on_delete=models.CASCADE,
        verbose_name=_('school'), limit_choices_to={'active': True}
    )
    date_time = models.DateTimeField(
        default=timezone.now, verbose_name=_('date and time')
    )

    def __str__(self):
        if self.site is not None:
            return self.site.site_name + ' album ' + str(self.id)
        else:
            return _('Unspecified site for album ') + str(self.id)

    class Meta:
        verbose_name = _('gallery album')
        verbose_name_plural = _('gallery albums')

class GalleryImage(models.Model):
    title = models.CharField(max_length=250,
                             verbose_name=_('title'))
    description = models.TextField(blank=True, verbose_name=_('description'))
    site = models.ForeignKey(
        Site, null=True, on_delete=models.CASCADE,
        verbose_name=_('Stream/Site name'), limit_choices_to={'active': True}
    )
    school = models.ForeignKey(
        School, null=True, on_delete=models.CASCADE,
        verbose_name=_('school'), limit_choices_to={'active': True}
    )
    user = models.ForeignKey(User, null=True, verbose_name=_('user'))
    album = models.ForeignKey(
        GalleryAlbum, null=True, blank=True, on_delete=models.CASCADE,
        verbose_name=_('album')
    )
    image = models.ImageField(null=True,
                              upload_to='gallery_images/',
                              verbose_name=_('image'))
    date_time = models.DateTimeField(
        default=timezone.now, verbose_name=_('date and time')
    )

    def filename(self):
        return os.path.basename(self.image.name)

    def __str__(self):
        if self.site is not None:
            if self.album is not None:
                return self.site.site_name + ' gallery image ' + str(self.id)\
                       + ' (Album ' + str(self.album.id) + ')'
            else:
                return self.site.site_name + ' gallery image ' + str(self.id)
        else:
            return _('Unspecified site for gallery image ') + str(self.id)

    class Meta:
        verbose_name = _('gallery image')
        verbose_name_plural = _('gallery images')

class GalleryFile(models.Model):
    title = models.CharField(max_length=250,
                             verbose_name=_('title'))
    description = models.TextField(blank=True, verbose_name=_('description'))
    site = models.ForeignKey(
        Site, null=True, on_delete=models.CASCADE,
        verbose_name=_('Stream/Site name'), limit_choices_to={'active': True}
    )
    school = models.ForeignKey(
        School, null=True, on_delete=models.CASCADE,
        verbose_name=_('school'), limit_choices_to={'active': True}
    )
    user = models.ForeignKey(User, null=True, verbose_name=_('user'))
    gallery_file = models.FileField(null=True, upload_to='gallery_files/',
                                    verbose_name=_('file'))
    date_time = models.DateTimeField(
        default=timezone.now, verbose_name=_('date and time')
    )

    def filename(self):
        return os.path.basename(self.gallery_file.name)

    def __str__(self):
        if self.site is not None:
            return self.site.site_name + ' file ' + str(self.id) +\
                    '(' + self.filename() + ')'
        else:
            return _('Unspecified site for file ') + str(self.id)

    class Meta:
        verbose_name = _('gallery file')
        verbose_name_plural = _('gallery files')

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    school = models.ForeignKey(School, on_delete=models.CASCADE)
    approved = models.BooleanField(default=False)

    def __unicode__(self):
        return self.user.username

class WaterQualityManager(models.Manager):
    """
    Manager for the Water_Quality model/datasheet.
    """
    def create_water_quality(self, site, date_time, school, DEQ_dq_level,
                             latitude, longitude, fish_present,
                             live_fish, dead_fish, air_temp_unit,
                             water_temp_unit, notes=''):

        wq_info = self.create(site=site,
                              date_time=date_time,
                              school=school,
                              DEQ_dq_level=DEQ_dq_level,
                              latitude=latitude,
                              longitude=longitude,
                              fish_present=fish_present,
                              live_fish=live_fish,
                              dead_fish=dead_fish,
                              air_temp_unit=air_temp_unit,
                              water_temp_unit=water_temp_unit,
                              notes=notes)
        return wq_info

def validate_WaterQuality_latitude(latitude):
    if abs(latitude) > 90:
        raise ValidationError(_('Latitude is not within valid range.'))

def validate_WaterQuality_longitude(longitude):
    if abs(longitude) > 180:
        raise ValidationError(_('Longitude is not within valid range.'))

@python_2_unicode_compatible
class Water_Quality(models.Model):
    """
    The Water Quality model corresponds to the Water Quality datasheet. Each
    object has a one-to-one relationship with its specified Site.
    """
    LEVEL_A = 'A'   # Define DEQ water quality levels
    LEVEL_B = 'B'
    LEVEL_C = 'C'
    LEVEL_D = 'D'
    LEVEL_E = 'E'
    FAHRENHEIT = _('Fahrenheit')
    CELSIUS = _('Celsius')

    DEQ_DQ_CHOICES = (
        (None, '-----'),
        (LEVEL_A, _('Level A')),
        (LEVEL_B, _('Level B')),
        (LEVEL_C, _('Level C')),
        (LEVEL_D, _('Level D')),
        (LEVEL_E, _('Level E')),
    )

    BOOL_CHOICES = (('True', _('Yes')), ('False', _('No')))
    UNIT_CHOICES = ((FAHRENHEIT, _('Fahrenheit')), (CELSIUS, _('Celsius')))

    site = models.ForeignKey(
        Site, null=True, on_delete=models.CASCADE,
        verbose_name=_('Stream/Site name'), limit_choices_to={'active': True}
    )
    date_time = models.DateTimeField(
        default=timezone.now, verbose_name=_('date and time')
    )
    DEQ_dq_level = models.CharField(
        max_length=10, choices=DEQ_DQ_CHOICES, blank=True,
        default=None, null=True, verbose_name=_('DEQ data quality level')
    )
    school = models.ForeignKey(
        School, null=True, on_delete=models.CASCADE,
        verbose_name=_('school'), limit_choices_to={'active': True}
    )
    latitude = models.DecimalField(
        null=True, max_digits=9, decimal_places=6,
        verbose_name=_('latitude'), validators=[validate_WaterQuality_latitude]
    )
    longitude = models.DecimalField(
        null=True, max_digits=9, decimal_places=6,
        verbose_name=_('longitude'),
        validators=[validate_WaterQuality_longitude]
    )
    fish_present = models.CharField(
        max_length=255, choices=BOOL_CHOICES, default=0, null=True,
        verbose_name=_('any fish present?')
    )
    live_fish = models.PositiveSmallIntegerField(
        default=0, null=True, verbose_name=_('number of live fish')
    )
    dead_fish = models.PositiveSmallIntegerField(
        default=0, null=True, verbose_name=_('number of dead fish')
    )
    water_temp_unit = models.CharField(
        max_length=255, choices=UNIT_CHOICES, default=0, null=True,
        verbose_name=_('water temperature units')
    )
    air_temp_unit = models.CharField(
        max_length=255, choices=UNIT_CHOICES, default=0, null=True,
        verbose_name=_('air temperature units')
    )
    notes = models.TextField(blank=True, verbose_name=_('notes'))
    nid = models.PositiveIntegerField(blank=True, null=True)

    # Uid used to make relations between school and data sheet
    uid = models.PositiveIntegerField(blank=True, null=True)

    test_objects = WaterQualityManager()
    objects = models.Manager()

    def __str__(self):
        if self.site is not None:
            return self.site.site_name + ' data sheet ' + str(self.id)
        else:
            return _('Unspecified site for data sheet ') + str(self.id)

    def to_dict(self):
        samples = WQ_Sample.objects.filter(water_quality=self)
        return {
            'DEQ_dq_level': self.DEQ_dq_level,
            'date': _timestamp(self.date_time),
            'school': self.school,
            'location': {
                'x': str(self.longitude),
                'y': str(self.latitude)
            },
            'fish_present': self.fish_present,
            'live_fish': self.live_fish,
            'dead_fish': self.dead_fish,
            'air_temp_unit': self.air_temp_unit,
            'water_temp_unit': self.water_temp_unit,
            'notes': self.notes,
            'samples': [m.to_dict() for m in samples]
        }

    class Meta:
        verbose_name = 'water quality'
        verbose_name_plural = 'water quality'

class WQSampleManager(models.Manager):
    """
    Manager for the water quality samples - creates both the required and
    additional field data for the Water Quality datasheet tests
    """
    def create_sample(
        self, water_quality, sample, water_temperature, water_temp_tool,
        air_temperature, air_temp_tool, dissolved_oxygen, oxygen_tool, pH,
        pH_tool, turbidity, turbid_tool, salinity, salt_tool,
        conductivity=None, total_solids=None, bod=None, ammonia=None,
        nitrite=None, nitrate=None, phosphates=None, fecal_coliform=None
    ):
        info = self.create(
            water_quality=water_quality,
            sample=sample,
            water_temperature=water_temperature,
            water_temp_tool=water_temp_tool,
            air_temperature=air_temperature,
            air_temp_tool=air_temp_tool,
            dissolved_oxygen=dissolved_oxygen,
            oxygen_tool=oxygen_tool,
            pH=pH,
            pH_tool=pH_tool,
            turbidity=turbidity,
            turbid_tool=turbid_tool,
            salinity=salinity,
            salt_tool=salt_tool,
            conductivity=conductivity,
            total_solids=total_solids,
            bod=bod,
            ammonia=ammonia,
            nitrite=nitrite,
            nitrate=nitrate,
            phosphates=phosphates,
            fecal_coliform=fecal_coliform
        )
        return info

def validate_pH(ph):
    if not(0 <= ph <= 14):
        raise ValidationError(
            '%(ph)s is not 0-14.',
            params={'ph': ph},
        )

@python_2_unicode_compatible
class WQ_Sample(models.Model):
    """
    The WQ_Sample model describes each water quality sample
    """
    NOT_ACCESSED = 'N/A'
    VERNIER = _('Vernier')
    MANUAL = _('Manual')
    TOOL_CHOICES = ((MANUAL, _('Manual')), (VERNIER, _('Vernier')),)

    # These are required fields
    water_quality = models.ForeignKey(
        Water_Quality,
        on_delete=models.CASCADE,
        related_name='water_quality',
        null=True
    )
    DEFAULT = '(Select a sample number)'
    ONE = 1
    TWO = 2
    THREE = 3
    FOUR = 4
    TOOL_CHOICES = ((NOT_ACCESSED, None),
                    (MANUAL, _('Manual')),
                    (VERNIER, _('Vernier')),)
    SAMPLE_CHOICES = ((DEFAULT, _('(Select a sample number)')),
                      (ONE, 1),
                      (TWO, 2),
                      (THREE, 3),
                      (FOUR, 4),)

    # These are required fields
    water_quality = models.ForeignKey(Water_Quality, on_delete=models.CASCADE,
                                      related_name='water_quality', null=True)
    sample = models.CharField(max_length=255, choices=SAMPLE_CHOICES,
                              null=True, default=SAMPLE_CHOICES[0])
    water_temperature = models.DecimalField(
        default=None, max_digits=5, decimal_places=2, null=True,
        verbose_name=_('water temperature')
    )
    water_temp_tool = models.CharField(
        max_length=255, choices=TOOL_CHOICES, default=NOT_ACCESSED, null=True,
    )
    air_temperature = models.DecimalField(
        default=None, null=True, max_digits=5, decimal_places=2,
        verbose_name=_('air temperature')
    )
    air_temp_tool = models.CharField(
        max_length=255, choices=TOOL_CHOICES, default=NOT_ACCESSED, null=True,
    )
    dissolved_oxygen = models.DecimalField(
        default=None, max_digits=5, decimal_places=2, null=True,
        verbose_name=_('dissolved oxygen (mg/L)')
    )
    oxygen_tool = models.CharField(
        max_length=255, choices=TOOL_CHOICES, default=NOT_ACCESSED, null=True,
    )
    pH = models.DecimalField(
        validators=[validate_pH], default=None, null=True,
        max_digits=5, decimal_places=2, verbose_name=_('pH')
    )
    pH_tool = models.CharField(
        max_length=255, choices=TOOL_CHOICES, default=NOT_ACCESSED, null=True
    )
    turbidity = models.DecimalField(
        default=None, null=True, max_digits=5, decimal_places=2,
        verbose_name=_('turbidity (NTU)')
    )
    turbid_tool = models.CharField(
        max_length=255, choices=TOOL_CHOICES, default=NOT_ACCESSED, null=True,
    )
    salinity = models.DecimalField(
        default=None, null=True, max_digits=5, decimal_places=2,
        verbose_name=_('salinity (PSU) PPT')
    )
    salt_tool = models.CharField(
        max_length=255, choices=TOOL_CHOICES, default=NOT_ACCESSED, null=True
    )
    # The following are optional fields
    conductivity = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True,
        null=True, verbose_name=_('conductivity (µS/cm)')
    )
    total_solids = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True,
        null=True, verbose_name=_('total solids (mg/L)')
    )
    bod = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True,
        null=True, verbose_name=_('BOD (mg/L)')
    )
    ammonia = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True,
        null=True, verbose_name=_('ammonia (mg/L)')
    )
    nitrite = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True,
        null=True, verbose_name=_('nitrite (mg/L)')
    )
    nitrate = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True,
        null=True, verbose_name=_('nitrate (mg/L)')
    )
    phosphates = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True,
        null=True, verbose_name=_('phosphates (mg/L)')
    )
    fecal_coliform = models.DecimalField(
        max_digits=5,
        decimal_places=2, blank=True,
        null=True,
        verbose_name=_('fecal coliform (CFU/100 mL)')
    )
    nid = models.PositiveIntegerField(blank=True, null=True)

    test_objects = WQSampleManager()
    objects = models.Manager()

    def __str__(self):
        if self.water_quality.site is not None:
            return self.water_quality.site.site_name + ' sheet ' + \
                str(self.water_quality.id) + ' sample ' + str(self.sample)
        else:
            return ' Unspecified site: sheet ' + \
                str(self.water_quality.id) + ' sample ' + str(self.sample)

    def to_dict(self):
        return {
            'water_temperature': str(_temp_conv(self.water_temperature,
                                     self.water_quality.water_temp_unit)),
            'water_temp_tool': self.water_temp_tool,
            'air_temperature': str(_temp_conv(self.air_temperature,
                                   self.water_quality.air_temp_unit)),
            'air_temp_tool': self.air_temp_tool,
            'dissolved_oxygen': str(self.dissolved_oxygen),
            'oxygen_tool': self.oxygen_tool,
            'pH': str(self.pH),
            'pH_tool': self.pH_tool,
            'turbidity': str(self.turbidity),
            'turbid_tool': self.turbid_tool,
            'salinity': str(self.salinity),
            'salt_tool': self.salt_tool,
            'conductivity': str(self.conductivity),
            'total_solids': str(self.total_solids),
            'bod': str(self.bod),
            'ammonia': str(self.ammonia),
            'nitrite': str(self.nitrite),
            'nitrate': str(self.nitrate),
            'phosphates': str(self.phosphates),
            'fecal_coliform': str(self.fecal_coliform)
        }

    class Meta:
        verbose_name = 'water quality sample'
        verbose_name_plural = 'water quality samples'

class CameraPointManager(models.Manager):

    def create_camera_point(self, site, cp_date, location, map_datum='',
                            description=''):

        return self.create(site=site, cp_date=cp_date, location=location,
                           map_datum=map_datum, description=description)

class CameraPoint(models.Model):
    map_datum_choices = [
        (None, 'Not Recorded'),
        ('NAD27', _('NAD 27 CONUS')),
        ('NAD83', _('NAD 83')),
        ('WGS84', _('WGS84')),
    ]

    site = models.ForeignKey(Site, on_delete=models.CASCADE, null=True)
    letter = models.CharField(null=True, max_length=5, editable=False)
    cp_date = models.DateField(default=datetime.date.today,
                               verbose_name=_('date established'))
    school = models.ForeignKey(School, null=True, on_delete=models.CASCADE,
                               verbose_name=_('school'))
    location = models.PointField(null=True, verbose_name=_('location'))
    map_datum = models.CharField(
        max_length=5, null=True, blank=True, verbose_name=_('map datum'),
        choices=map_datum_choices, default=None)
    description = models.TextField(blank=True, verbose_name=_('description'))
    created = models.DateTimeField(default=timezone.now)

    test_objects = CameraPointManager()
    objects = models.Manager()

    def __str__(self):
        return (_('Camera point ') + self.letter + _(' for site ') +
                self.site.site_name)

    def save(self, **kwargs):
        if not self.letter:
            site_cps = CameraPoint.objects.filter(site_id=self.site.id)
            if not site_cps.exists():
                self.letter = 'A'
            else:
                prev_letter = site_cps.latest('created').letter
                max_len = len(prev_letter)
                if prev_letter[0] == 'Z':
                    self.letter = (max_len + 1) * 'A'
                else:
                    self.letter = max_len * chr(ord(prev_letter[0]) + 1)
        super(CameraPoint, self).save()

    class Meta:
        verbose_name = _('camera point')
        verbose_name_plural = _('camera points')

class PhotoPointManager(models.Manager):

    def create_photo_point(self, camera_point, pp_date, compass_bearing,
                           distance, camera_height, notes=''):

        return self.create(camera_point=camera_point, pp_date=pp_date,
                           compass_bearing=compass_bearing, distance=distance,
                           camera_height=camera_height, notes=notes)

class PhotoPoint(models.Model):
    camera_point = models.ForeignKey(CameraPoint, on_delete=models.CASCADE,
                                     null=True, related_name='camera_point')
    number = models.PositiveSmallIntegerField(null=True, editable=False)
    pp_date = models.DateField(default=datetime.date.today,
                               verbose_name=_('date established'))
    compass_bearing = models.PositiveSmallIntegerField(
        verbose_name=_('compass bearing'))
    distance = models.DecimalField(
        max_digits=3, decimal_places=0, null=True, blank=True,
        verbose_name=_('distance from camera point'))
    camera_height = models.DecimalField(
        max_digits=3, decimal_places=0, null=True, blank=True,
        verbose_name=_('camera height'))
    notes = models.TextField(blank=True, verbose_name=_('notes'))

    test_objects = PhotoPointManager()
    objects = models.Manager()

    def __str__(self):
        return (_('Photo point ') + str(self.number) + _(' for camera point ')
                + self.camera_point.letter)

    def save(self, **kwargs):
        if not self.number:
            p = PhotoPoint.objects.filter(camera_point_id=self.camera_point.id)
            if not p.exists():
                self.number = 1
            else:
                prev_num = p.latest('number').number
                self.number = prev_num + 1
        super(PhotoPoint, self).save()

    class Meta:
        verbose_name = _('photo point')
        verbose_name_plural = _('photo points')

class PhotoPointImage(models.Model):
    photo_point = models.ForeignKey(PhotoPoint, on_delete=models.CASCADE,
                                    null=True, related_name='photo_point')
    image = models.ImageField(null=True, upload_to='pp_photos/',
                              verbose_name=_('photo'))
    date = models.DateField(default=datetime.date.today,
                            verbose_name=_('date taken'))

    def __str__(self):
        return (str(self.date) + _(' for photo point ') +
                str(self.photo_point.number))

    class Meta:
        verbose_name = _('photo point image')
        verbose_name_plural = _('photo point images')

class MacroinvertebratesManager(models.Manager):
    """
    Manager for the Macroinvertebrates model.
    """
    def create_macro(self, site, school, time_spent=0, num_people=0,
                     water_type='riff', caddisfly=0, mayfly=0, riffle_beetle=0,
                     stonefly=0, water_penny=0, dobsonfly=0, clam_or_mussel=0,
                     crane_fly=0, crayfish=0, damselfly=0, dragonfly=0, scud=0,
                     fishfly=0, alderfly=0, mite=0, aquatic_worm=0, blackfly=0,
                     leech=0, midge=0, snail=0, mosquito_larva=0, notes=''):

        info = self.create(school=school,
                           date_time='2016-07-11 14:09',
                           weather='bbbb',
                           site=site,
                           time_spent=time_spent,
                           num_people=num_people,
                           water_type=water_type,
                           caddisfly=caddisfly,
                           mayfly=mayfly,
                           riffle_beetle=riffle_beetle,
                           stonefly=stonefly,
                           water_penny=water_penny,
                           dobsonfly=dobsonfly,
                           clam_or_mussel=clam_or_mussel,
                           crane_fly=crane_fly,
                           crayfish=crayfish,
                           damselfly=damselfly,
                           dragonfly=dragonfly,
                           scud=scud,
                           fishfly=fishfly,
                           alderfly=alderfly,
                           mite=mite,
                           aquatic_worm=aquatic_worm,
                           blackfly=blackfly,
                           leech=leech,
                           midge=midge,
                           snail=snail,
                           mosquito_larva=mosquito_larva,
                           notes=notes)
        return info

@python_2_unicode_compatible
class Macroinvertebrates(models.Model):
    RIFFLE = 'riff'
    POOL = 'pool'

    WATER_TYPE_CHOICES = (
        (None, '-----'),
        (RIFFLE, _('riffle')),
        (POOL, _('pool')),
    )

    school = models.ForeignKey(School, null=True, on_delete=models.CASCADE,
                               verbose_name=_('school'))
    date_time = models.DateTimeField(default=timezone.now,
                                     verbose_name=_('date and time'))
    weather = models.CharField(max_length=250,
                               verbose_name=_('weather'))
    site = models.ForeignKey(Site, null=True, on_delete=models.CASCADE,
                             limit_choices_to={'active': True})
    time_spent = models.PositiveIntegerField(
        default=None, null=True,
        verbose_name=_('Time spent sorting/identifying')
        )
    num_people = models.PositiveIntegerField(
        default=None, null=True,
        verbose_name=_('Number of people sorting/identifying')
        )
    water_type = models.CharField(max_length=4, verbose_name=_('water type'),
                                  choices=WATER_TYPE_CHOICES, default=None,
                                  blank=True)
    notes = models.TextField(blank=True, verbose_name=_('field notes'))

    # Sensitive/intolerant to pollution
    caddisfly = models.PositiveIntegerField(default=0,
                                            verbose_name=_('caddisfly'))
    mayfly = models.PositiveIntegerField(default=0,
                                         verbose_name=_('mayfly'))
    riffle_beetle = models.PositiveIntegerField(
        default=0, verbose_name=_('riffle beetle')
        )
    stonefly = models.PositiveIntegerField(default=0,
                                           verbose_name=_('stonefly'))
    water_penny = models.PositiveIntegerField(default=0,
                                              verbose_name=_('water penny'))
    dobsonfly = models.PositiveIntegerField(default=0,
                                            verbose_name=_('dobsonfly'))
    sensitive_total = models.PositiveIntegerField(
        default=0, verbose_name=_('sensitive total')
        )

    # Somewhat sensitive
    clam_or_mussel = models.PositiveIntegerField(default=0,
                                                 verbose_name=_('clam/mussel'))
    crane_fly = models.PositiveIntegerField(default=0,
                                            verbose_name=_('crane fly'))
    crayfish = models.PositiveIntegerField(default=0,
                                           verbose_name=_('crayfish'))
    damselfly = models.PositiveIntegerField(default=0,
                                            verbose_name=_('damselfly'))
    dragonfly = models.PositiveIntegerField(default=0,
                                            verbose_name=_('dragonfly'))
    scud = models.PositiveIntegerField(default=0, verbose_name=_('scud'))
    fishfly = models.PositiveIntegerField(default=0, verbose_name=_('fishfly'))
    alderfly = models.PositiveIntegerField(default=0,
                                           verbose_name=_('alderfly'))
    mite = models.PositiveIntegerField(default=0, verbose_name=_('mite'))
    somewhat_sensitive_total = models.PositiveIntegerField(
        default=0, verbose_name=_('somewhat sensitive total')
        )

    # Tolerant
    aquatic_worm = models.PositiveIntegerField(default=0,
                                               verbose_name=_('aquatic worm'))
    blackfly = models.PositiveIntegerField(default=0,
                                           verbose_name=_('blackfly'))
    leech = models.PositiveIntegerField(default=0, verbose_name=_('leech'))
    midge = models.PositiveIntegerField(default=0, verbose_name=_('midge'))
    snail = models.PositiveIntegerField(default=0, verbose_name=_('snail'))
    mosquito_larva = models.PositiveIntegerField(
        default=0, verbose_name=_('mosquito larva')
        )
    tolerant_total = models.PositiveIntegerField(
        default=0, verbose_name=_('tolerant total')
        )

    # Water quality rating
    wq_rating = models.PositiveIntegerField(
        default=0, verbose_name=_('water quality rating')
        )

    # Uid used to make relations between school and data sheet
    uid = models.PositiveIntegerField(blank=True, null=True)

    objects = models.Manager()
    test_objects = MacroinvertebratesManager()

    def __str__(self):
        return self.site.site_name + ' sheet ' + str(self.id)

    def calculate_scores(self):
        self.sensitive_total = 0
        self.somewhat_sensitive_total = 0
        self.tolerant_total = 0

        # divvy up indiv count values into three arrays
        sensitive = [self.caddisfly, self.mayfly, self.riffle_beetle,
                     self.stonefly, self.water_penny, self.dobsonfly]
        somewhat = [self.clam_or_mussel, self.crane_fly, self.crayfish,
                    self.damselfly, self.dragonfly, self.scud, self.fishfly,
                    self.alderfly, self.mite]
        tolerant = [self.aquatic_worm, self.blackfly, self.leech, self.midge,
                    self.snail, self.mosquito_larva]

        # loop thru each array-- if a bug's count is at least one, that bug
        # gets n points towards its category's final score (n = 3 for
        # sensitive, n = 2 for somewhat sensitive, n = 1 for tolerant)
        for count in sensitive:
            if count > 0:
                self.sensitive_total += 3

        for count in somewhat:
            if count > 0:
                self.somewhat_sensitive_total += 2

        for count in tolerant:
            if count > 0:
                self.tolerant_total += 1

    def save(self, **kwargs):
        self.calculate_scores()

        # the water quality rating is just the sum of the three scores
        self.wq_rating = (self.sensitive_total +
                          self.somewhat_sensitive_total + self.tolerant_total)

        super(Macroinvertebrates, self).save()

    class Meta:
        verbose_name = _('macroinvertebrate')
        verbose_name_plural = _('macroinvertebrates')

    def get_tolerant_counts(self):
        return [
            {'name': _('Aquatic Worm'), 'value': self.aquatic_worm},
            {'name': _('Blackfly'), 'value': self.blackfly},
            {'name': _('Leech'), 'value': self.leech},
            {'name': _('Midge'), 'value': self.midge},
            {'name': _('Snail'), 'value': self.snail},
            {'name': _('Mosquito Larva'), 'value': self.mosquito_larva}
        ]

    def get_somewhat_sensitive_counts(self):
        return [
            {'name': _('Mussel/Clam'), 'value': self.clam_or_mussel},
            {'name': _('Crane Fly'), 'value': self.crane_fly},
            {'name': _('Crayfish'), 'value': self.crayfish},
            {'name': _('Damselfly'), 'value': self.damselfly},
            {'name': _('Dragonfly'), 'value': self.dragonfly},
            {'name': _('Scud'), 'value': self.scud},
            {'name': _('Fishfly'), 'value': self.fishfly},
            {'name': _('Alderfly'), 'value': self.alderfly},
            {'name': _('Mite'), 'value': self.mite}
        ]

    def get_sensitive_counts(self):
        return [
            {'name': _('Riffle Beetle'), 'value': self.riffle_beetle},
            {'name': _('Mayfly'), 'value': self.mayfly},
            {'name': _('Water Penny'), 'value': self.water_penny},
            {'name': _('Stonefly'), 'value': self.stonefly},
            {'name': _('Caddisfly'), 'value': self.caddisfly},
            {'name': _('Dobsonfly'), 'value': self.dobsonfly}
        ]

    def get_totals(self):
        # total number of somewhat sensitive macros found:
        somewhat = (int(self.clam_or_mussel) + int(self.crane_fly) +
                    int(self.crayfish) + int(self.damselfly) +
                    int(self.dragonfly) + int(self.scud) + int(self.fishfly) +
                    int(self.alderfly) + int(self.mite))

        # total number of sensitive macros found:
        sensitive = (int(self.caddisfly) + int(self.mayfly) +
                     int(self.riffle_beetle) + int(self.stonefly) +
                     int(self.water_penny) + int(self.dobsonfly))

        # total number of tolerant macros found:
        tolerant = (int(self.aquatic_worm) + int(self.blackfly) +
                    int(self.leech) + int(self.midge) + int(self.snail) +
                    int(self.mosquito_larva))

        return {
            _('Tolerant'): tolerant,
            _('Somewhat Sensitive'): somewhat,
            _('Sensitive'): sensitive
        }

class RipTransectManager(models.Manager):
    """
    Manager for the RiparianTransect model/datasheet.
    """
    def create_transect(self, school, date_time, site, weather='', slope=None,
                        notes=''):
        return self.create(school=school, date_time=date_time, site=site,
                           weather=weather, slope=slope, notes=notes)

def validate_slope(slope):
    if not(0 <= slope):
        raise ValidationError(
            '%(slope)s is not positive.',
            params={'slope': slope},
            )

class RiparianTransect(models.Model):
    """
    This model corresponds to the Riparian Transect data sheet and has a one-to
    -one relationship with its specified Site.
    """
    school = models.ForeignKey(School, null=True, on_delete=models.CASCADE,
                               verbose_name=_('school'))
    date_time = models.DateTimeField(default=timezone.now,
                                     verbose_name=_('date and time'))
    weather = models.CharField(max_length=255, blank=True,
                               verbose_name=_('weather'))
    site = models.ForeignKey(Site, null=True, on_delete=models.CASCADE,
                             verbose_name=_('site'),
                             limit_choices_to={'active': True})
    slope = models.DecimalField(
        blank=True, null=True, max_digits=5, decimal_places=3,
        verbose_name=_('slope of stream bank (rise over run)')
    )
    notes = models.TextField(blank=True, verbose_name=_('notes'))
    nid = models.PositiveIntegerField(blank=True, null=True)

    # Uid used to make relations between school and data sheet
    uid = models.PositiveIntegerField(blank=True, null=True)

    test_objects = RipTransectManager()
    objects = models.Manager()

    def __str__(self):
        return (_('Transect ') + str(self.id) + _(' for site ')
                + self.site.site_name)

    class Meta:
        verbose_name = _('riparian transect')
        verbose_name_plural = _('riparian transects')

class TransectZoneManager(models.Manager):
    """
    Manager for the TransectZone model.
    """
    def create_zone(self, transect, conifers=0, hardwoods=0, shrubs=0,
                    comments=''):
        return self.create(transect=transect, conifers=conifers,
                           hardwoods=hardwoods, shrubs=shrubs,
                           comments=comments)

class TransectZone(models.Model):
    """
    Each Riparian Transect datasheet requires five zones.
    """
    ZONE_1 = 1
    ZONE_2 = 2
    ZONE_3 = 3
    ZONE_4 = 4
    ZONE_5 = 5

    ZONES = ((ZONE_1, 1), (ZONE_2, 2), (ZONE_3, 3), (ZONE_4, 4), (ZONE_5, 5))

    transect = models.ForeignKey(RiparianTransect, on_delete=models.CASCADE,
                                 related_name='transect', null=True)
    zone_num = models.CharField(max_length=1, default=0, choices=ZONES)
    conifers = models.PositiveSmallIntegerField(default=0, null=True,
                                                verbose_name=_('conifers'))
    hardwoods = models.PositiveSmallIntegerField(default=0, null=True,
                                                 verbose_name=_('hardwoods'))
    shrubs = models.PositiveSmallIntegerField(default=0, null=True,
                                              verbose_name=_('shrubs'))
    comments = models.TextField(blank=True, default='',
                                verbose_name=_('additional comments'))

    test_objects = TransectZoneManager()
    objects = models.Manager()

    def __str__(self):
        return ('Zone ' + str(self.zone_num) + ' for transect ' +
                str(self.transect.id))

    class Meta:
        verbose_name = 'zone'
        verbose_name_plural = 'zones'

def validate_cover(canopy_cover):
    if canopy_cover & 0b11111111000000000000000000000000 != 0:
        raise ValidationError(
            '%(canopy_cover)s has bad bits set.',
            params={'canopy_cover': canopy_cover},
            )

def validate_total_cover(est_canopy_cover):
    if not(0 <= est_canopy_cover and est_canopy_cover <= 96):
        raise ValidationError(
            '%(est_canopy_cover)s is not 0-96.',
            params={'est_canopy_cover': est_canopy_cover},
            )

@python_2_unicode_compatible
class Canopy_Cover(models.Model):
    school = models.ForeignKey(School, null=True, on_delete=models.CASCADE,
                               verbose_name=_('school'))
    date_time = models.DateTimeField(default=timezone.now,
                                     verbose_name=_('date and time'))
    site = models.ForeignKey(Site, null=True, on_delete=models.CASCADE,
                             verbose_name=_('site'))
    weather = models.CharField(max_length=250, verbose_name=_('weather'))
    north_cc = models.IntegerField(
        default=0, validators=[validate_cover],
        verbose_name=_('north canopy cover')
        )
    east_cc = models.IntegerField(
        default=0, validators=[validate_cover],
        verbose_name=_('east canopy cover')
        )
    south_cc = models.IntegerField(
        default=0, validators=[validate_cover],
        verbose_name=_('south canopy cover')
        )
    west_cc = models.IntegerField(
        default=0, validators=[validate_cover],
        verbose_name=_('west canopy cover')
        )
    est_canopy_cover = models.PositiveIntegerField(
        default=0, validators=[validate_total_cover],
        verbose_name=_('estimated canopy cover')
        )

    # Uid used to make relations between school and data sheet
    uid = models.PositiveIntegerField(blank=True, null=True)

    def __str__(self):
        return(str(self.date_time) + ' ' + self.site.site_name)

    class Meta:
        verbose_name = _('canopy cover survey')
        verbose_name_plural = _('canopy cover surveys')

@python_2_unicode_compatible
class Soil_Survey(models.Model):
    school = models.ForeignKey(School, null=True, on_delete=models.CASCADE,
                               verbose_name=_('school'))
    date_time = models.DateTimeField(default=timezone.now,
                                     verbose_name=_('date and time'))
    weather = models.CharField(max_length=250, verbose_name=_('weather'),
                               blank=True)
    site = models.ForeignKey(Site, null=True, on_delete=models.CASCADE,
                             verbose_name=_('site'))
    notes = models.TextField(blank=True, verbose_name=_("Field notes"))

    landscape_pos_choices = [
        ('summit', _('Summit')),
        ('slope', _('Slope')),
        ('depression', _('Depression')),
        ('large_flat', _('Large Flat Area')),
        ('stream_bank', _('Stream Bank'))
    ]

    cover_type_choices = [
        ('bare_soil', _('Bare Soil')),
        ('rocks', _('Rocks')),
        ('grass', _('Grass')),
        ('shrubs', _('Shrubs')),
        ('trees', _('Trees'))
    ]

    land_use_choices = [
        ('urban', _('Urban')),
        ('agricultural', _('Agricultural')),
        ('recreation', _('Recreation')),
        ('wilderness', _('Wilderness')),
        ('other', _('Other'))
    ]

    landscape_pos = models.CharField(max_length=11, default=None,
                                     choices=landscape_pos_choices,
                                     verbose_name='landscape position')

    cover_type = models.CharField(max_length=9, default=None,
                                  choices=cover_type_choices)

    land_use = models.CharField(max_length=12, default=None,
                                choices=land_use_choices)

    distance = models.DecimalField(max_digits=5, decimal_places=2, null=True,
                                   verbose_name=_('distance from stream'))

    site_char = models.TextField(blank=True,
                                 verbose_name=_('distinguishing site \
                                 characteristics'))

    soil_type_choices = [
        ('sand', _('Sand')),
        ('loamy_sand', _('Loamy Sand')),
        ('silt_loam', _('Silt Loam')),
        ('loam', _('Loam')),
        ('clay_loam', _('Clay Loam')),
        ('light_clay', _('Light Clay')),
        ('heavy_clay', _('Heavy Clay')),
        ('n/a', _('N/A')),
        ('other', _('Other'))
    ]

    soil_type = models.CharField(max_length=10, default=None, blank=False,
                                 choices=soil_type_choices)

    # Uid used to make relations between school and data sheet
    uid = models.PositiveIntegerField(blank=True, null=True)

    def __str__(self):
        return self.site.site_name

    class Meta:
        verbose_name = _('soil survey')
        verbose_name_plural = _('soil surveys')

class ResourceManager(models.Model):
    """ Manager for the Resources model """
    def create_resource(
        self, name, res_type, downloadable, thumbnail, sort_order
    ):
        return self.create(
            name=name, res_type=res_type, downloadable=downloadable,
            thumbnail=thumbnail, sort_order=sort_order
        )

class Resource(models.Model):
    """ This model organizes Resources like pdfs or videos """
    TYPE_CHOICES = (
        (None, '-----'),
        ('data_sheet', _('Data Sheet')),
        ('publication', _('Publication')),
        ('tutorial_video', _('Tutorial Video')),
    )
    name = models.CharField(max_length=255, blank=False)
    res_type = models.CharField(
        max_length=255, blank=False, choices=TYPE_CHOICES
    )
    # bad way to handle upload_to!  It should be based on res_type
    downloadable = models.FileField(upload_to='assets/', blank=True)
    thumbnail = models.ImageField(upload_to='assets/thumbnails/', blank=True)
    sort_order = models.PositiveSmallIntegerField(default=1000)

    objects = models.Manager()
    test_objects = ResourceManager()

    class Meta:
        verbose_name = _('resource')
        verbose_name_plural = _('resources')

    def __str__(self):
        return self.name

    @property
    def thumbnail_url(self):
        if self.thumbnail and hasattr(self.thumbnail, 'url'):
            return self.thumbnail.url

class RipAquaticSurveyManager(models.Manager):

    def create_aqua(self, site, school, date_time='2016-04-03 12:00',
                    riffle_count=3, pool_count=3, weather='RAAIIN'):

        info = self.create(school=school,
                           site=site,
                           weather=weather,
                           riffle_count=riffle_count,
                           pool_count=pool_count)
        return info

class RipAquaticSurvey(models.Model):
    OPTIONS = (
            ('Very Little', _('Very Little')),
            ('Some', _('Some')),
            ('A Lot', _('A Lot'))
            )
    school = models.ForeignKey(School, null=True, on_delete=models.CASCADE,
                               verbose_name=_('school'),
                               blank=False, default='',
                               limit_choices_to={'active': True}
                               )
    site = models.ForeignKey(Site, null=True, on_delete=models.CASCADE,
                             verbose_name=_('site'),
                             limit_choices_to={'active': True}
                             )
    date_time = models.DateTimeField(default=timezone.now,
                                     verbose_name=_('date and time'))
    weather = models.CharField(
        max_length=20, verbose_name=_('weather'), blank=True, null=True
    )
    stream_length = models.PositiveIntegerField(
        blank=True, null=True, verbose_name=_('length of stream')
    )
    riffle_count = models.PositiveIntegerField(
        blank=True, null=True, verbose_name=_('number of riffles')
    )
    pool_count = models.PositiveIntegerField(
        blank=True, null=True, verbose_name=_('number of pools')
    )
    silt = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('silt')
    )
    sand = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('sand')
    )
    gravel = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('gravel')
    )
    cobble = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('cobble')
    )
    boulders = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('boulders')
    )
    bedrock = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('bedrock')
    )
    small_debris = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('small_debris')
    )
    medium_debris = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('medium_debris')
    )
    large_debris = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('large_debris')
    )
    comments = models.CharField(
        max_length=250, null=True, verbose_name=_('comments'), blank=True
    )
    coniferous_trees = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('coniferous_trees')
    )
    deciduous_trees = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('deciduous_trees')
    )
    shrubs = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('shrubs')
    )
    small_plants = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('small_plants')
    )
    ferns = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('ferns')
    )
    grasses = models.CharField(
        max_length=250, choices=OPTIONS, null=True, blank=True,
        verbose_name=_('grasses')
    )
    species1 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('species')
    )
    species2 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('species')
    )
    species3 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('species')
    )
    species4 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('species')
    )
    species5 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('species')
    )
    species6 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('species')
    )
    significance1 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('significance to riparian area')
    )
    significance2 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('significance to riparian area')
    )
    significance3 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('significance to riparian area')
    )
    significance4 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('significance to riparian area')
    )
    significance5 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('significance to riparian area')
    )
    significance6 = models.CharField(
        max_length=250, null=True, blank=True,
        verbose_name=_('significance to riparian area')
    )
    wildlife_type1 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('type, species, or track/sign')
    )
    wildlife_type2 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('type, species, or track/sign')
    )
    wildlife_type3 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('type, species, or track/sign')
    )
    wildlife_type4 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('type, species, or track/sign')
    )
    wildlife_type5 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('type, species, or track/sign')
    )
    wildlife_type6 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('type, species, or track/sign')
    )
    wildlife_comments1 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('# or comments')
    )
    wildlife_comments2 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('# or comments')
    )
    wildlife_comments3 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('# or comments')
    )
    wildlife_comments4 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('# or comments')
    )
    wildlife_comments5 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('# or comments')
    )
    wildlife_comments6 = models.CharField(
        max_length=500, null=True, blank=True,
        verbose_name=_('# or comments')
    )
    notes = models.TextField(blank=True, verbose_name=_("Field notes"))
    objects = models.Manager()
    test_objects = RipAquaticSurveyManager()


# Laod all the libraries
from argparse import ArgumentParser

def read(path, filename):
    # read file
    with open(path + filename, 'r') as f:
        score = [line.rstrip('\n') for line in f]
        print(score)

if __name__ == "__main__":
    # Read the filepath for csv files from command line
    parser = ArgumentParser()
    # First input path where files are stored
    parser.add_argument("-p",
                        "--path",
                        help="input the filepath",
                        type = str)
    # Second input filename
    parser.add_argument("-f",
                        "--file",
                        help="input the filename",
                        type = str)
    args = parser.parse_args()
    path = args.path
    filename = args.file
    # Execute main
    read(path, filename)


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

import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
import os
from image_util import resize
from PIL import Image

tf.app.flags.DEFINE_string('checkpoint_dir', 'checkpoint/', """チェックポイント保存先""")
tf.app.flags.DEFINE_integer('max_step', 50000, """訓練回数""")
tf.app.flags.DEFINE_string('data_dir', './data', """訓練データパス""")
tf.app.flags.DEFINE_string('log_dir', 'logs/', """学習ログ出力先""")
tf.app.flags.DEFINE_boolean('eval', False, """評価モードフラグ""")
tf.app.flags.DEFINE_string('photo_file', "", """評価対象画像""")

FLAGS = tf.app.flags.FLAGS

LABEL2NAME = {0: "T-shirt/top", 1: "Trouser", 2: "Pullover", 3: "Dress",
              4: "Coat", 5: "Sandal", 6: "Shirts", 7: "Sneaker", 8: "Bag", 9: "Ankle boot"}

def training():
  data = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)

  x = tf.placeholder(tf.float32, [None, 784])
  y = tf.placeholder(tf.float32, [None, 10])
  kb = tf.placeholder(tf.float32, [])

  convolution_op = convolution(x, kb)
  loss_op = loss(convolution_op, y)
  train_op = train(loss_op)
  accuracy_op = accuracy(convolution_op, y)
  init_op = tf.global_variables_initializer()

  with tf.Session() as sess:
    saver = tf.train.Saver()
    load_checkpoint(sess, saver)
    summary_writer = tf.summary.FileWriter(FLAGS.log_dir, sess.graph)
    summary_op = tf.summary.merge_all()

    for i in range(FLAGS.max_step):
      images, labels = data.train.next_batch(32)
      _, _loss, _accuracy = sess.run((train_op, loss_op, accuracy_op), feed_dict={x: images, y: labels, kb: 0.5})
      if i % 10 == 0:
        print('step: %03d loss: %0.06f accuracy: %0.06f' % (i, _loss, _accuracy))
      if i % 500 == 0 or i == FLAGS.max_step - 1:
        test_image, test_label = data.test.next_batch(3000)
        _accuracy, _ = sess.run([accuracy_op, summary_op], feed_dict={x: test_image, y: test_label, kb: 1.0})
        print('Test accuracy: %s' % _accuracy)
        saver.save(sess, FLAGS.checkpoint_dir, global_step=i)

def convolution(images, keep_prob):
  batch_size = tf.shape(images)[0]
  reshape = tf.reshape(images, [batch_size, 28, 28, 1])

  output = tf.layers.conv2d(reshape, filters=32, kernel_size=5, strides=(2,2), padding='SAME')
  output = tf.nn.relu(output)

  output = tf.layers.conv2d(reshape, filters=64, kernel_size=5, padding='SAME')
  output = tf.nn.relu(output)

  output = tf.layers.max_pooling2d(output, pool_size=(2, 2), strides=1)

  output = tf.layers.dropout(output, rate=keep_prob)

  output = tf.layers.conv2d(reshape, filters=32, kernel_size=5, strides=(2,2), padding='SAME')
  output = tf.nn.relu(output)

  output = tf.layers.conv2d(reshape, filters=64, kernel_size=5, padding='SAME')
  output = tf.nn.relu(output)

  output = tf.layers.max_pooling2d(output, pool_size=(2, 2), strides=1)

  output = tf.layers.dropout(output, rate=keep_prob)

  output = tf.contrib.layers.flatten(output)

  output = tf.layers.dense(output, 512)
  output = tf.nn.relu(output)

  output = tf.layers.dropout(output, rate=keep_prob)

  output = tf.layers.dense(output, 10)
  output = tf.nn.softmax(output)
  return output

def load_checkpoint(sess, saver):
  if os.path.exists(FLAGS.checkpoint_dir + 'checkpoint'):
    print('restore parameters...')
    saver.restore(sess, tf.train.latest_checkpoint(FLAGS.checkpoint_dir))
  else:
    print('initilize parameters...')
    init_op = tf.global_variables_initializer()
    sess.run(init_op)

def loss(logits, labels):
  loss = tf.reduce_mean(-tf.reduce_sum(labels * tf.log(logits + 1e-10), reduction_indices=[1]))
  tf.summary.scalar('loss', loss)
  return loss

def train(loss):
  return tf.train.AdadeltaOptimizer().minimize(loss)

def accuracy(logits, labels):
  correct_prediction = tf.equal(tf.argmax(logits,1), tf.argmax(labels,1))
  accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
  tf.summary.scalar('accuracy', accuracy)
  return accuracy

def evaluate():
  img = Image.open(FLAGS.photo_file)
  gray_img = img.convert('L')
  img = [int(e) / 255.0 for e in resize(gray_img).tobytes()]
  x = tf.placeholder(tf.float32, [None, 784])
  kb = tf.placeholder(tf.float32, [])
  convolution_op = convolution(x, kb)
  with tf.Session() as sess:
    saver = tf.train.Saver()
    load_checkpoint(sess, saver)
    logits = sess.run([convolution_op], feed_dict={x: [img], kb: 1.0})
    print(LABEL2NAME[np.argmax(logits[0])])

def main():
  if FLAGS.eval:
    evaluate()
  else:
    training()

if __name__ == '__main__':
  main()


# coding: utf-8

from __future__ import absolute_import

from swagger_server.models.error import Error
from swagger_server.models.generic_object import GenericObject
from swagger_server.models.uid_info import UidInfo
from . import BaseTestCase
from six import BytesIO
from flask import json

class TestUidController(BaseTestCase):
    """ UidController integration test stubs """

    def test_root_get(self):
        """
        Test case for root_get

        Returns the current versions information
        """
        response = self.client.open('/v1/',
                                    method='GET')
        self.assert200(response, "Response body is : " + response.data.decode('utf-8'))

    def test_root_post(self):
        """
        Test case for root_post

        creates a new uid
        """
        response = self.client.open('/v1/',
                                    method='POST')
        self.assert200(response, "Response body is : " + response.data.decode('utf-8'))

    def test_uid_delete(self):
        """
        Test case for uid_delete

        delete a uid
        """
        response = self.client.open('/v1/{uid}'.format(uid=789),
                                    method='DELETE',
                                    content_type='application/json')
        self.assert200(response, "Response body is : " + response.data.decode('utf-8'))

    def test_uid_get(self):
        """
        Test case for uid_get

        get the particular uid for the version
        """
        response = self.client.open('/v1/{uid}'.format(uid=789),
                                    method='GET',
                                    content_type='application/json')
        self.assert200(response, "Response body is : " + response.data.decode('utf-8'))

    def test_uid_post(self):
        """
        Test case for uid_post

        update an existing uid
        """
        body = GenericObject()
        response = self.client.open('/v1/{uid}'.format(uid=789),
                                    method='POST',
                                    data=json.dumps(body),
                                    content_type='application/json')
        self.assert200(response, "Response body is : " + response.data.decode('utf-8'))

    def test_uid_put(self):
        """
        Test case for uid_put

        update an existing uid
        """
        body = GenericObject()
        response = self.client.open('/v1/{uid}'.format(uid=789),
                                    method='PUT',
                                    data=json.dumps(body),
                                    content_type='application/json')
        self.assert200(response, "Response body is : " + response.data.decode('utf-8'))

if __name__ == '__main__':
    import unittest
    unittest.main()


import json
import os
import copy

from .ApiBase import ApiBase
from package.mylib import mylib

class admin(ApiBase):
    '''
    后台管理相关
    '''

    def __init__(self, handler):
        super().__init__(handler)

        self.pluginpath = r'./plugin'
        self.default_admin = []
        admin_path = self.config['ADMIN']['config']
        with open(admin_path) as f:
            self.default_admin = json.load(f)
        del admin_path

    # 加载插件配置插件，所有插件只能有一个插件可以配置后台管理
    def __load_plugin_menu(self):
        admin_mneu = []

        for filedir in os.listdir(self.pluginpath):
            if os.path.isdir(os.path.join(self.pluginpath, filedir)) and filedir != '__pycache__':
                json_path = os.path.join(self.pluginpath, filedir, 'adminconfig.json')
                if os.path.isfile(json_path):
                    with open(json_path, 'r') as f:
                        admin_mneu = json.load(f)
                        return admin_mneu
        return admin_mneu

    # 加载后台管理菜单
    def __load_admin_menu(self):
        # admin_mneu = self.__load_plugin_menu()
        # if len(admin_mneu)>0:
        #     self.default_admin = admin_mneu

        return json.dumps(self.default_admin)

    def main(self):
        # 获取后台管理菜单
        if self.query['get']=='menu':
            return self.__load_admin_menu()


import cv2
import randomname
import datetime
import time
from VideoGet import VideoGet
from VideoShow import VideoShow
from RgbTest import RgbTest

class LifeCycle:
    def __init__(self):
        self.first_run = True
        self.name = ""
        self.born_dt = None
        self.born_text = ""
        self.death_text = ""
        self.age = ""
        self.dead = False

    def delay(self):
        time.sleep(5)

    def born(self):
        self.dead = False
        self.death_text = ""
        self.age = ""
        self.name = randomname.get_name()
        self.name = self.name.replace("-", " ")
        self.name = self.name.title()
        self.born_dt = datetime.datetime.now()
        self.born_text =  self.name + " Born " + self.born_dt.strftime("%d.%m.%Y At %H:%M:%S")

    def death(self):
        self.dead = True
        self.age = datetime.datetime.now() - self.born_dt
        minutes = divmod(self.age.seconds, 60)
        self.death_text = "Died " + datetime.datetime.now().strftime("%d.%m.%Y At %H:%M:%S")
        if minutes[0] == 0:
            self.age ="Aged " + str(minutes[1]) + " seconds"
        elif minutes[0] == 1:
            self.age = "Aged " + str(minutes[0]) + " minute " + str(minutes[1]) + " seconds"
        else:
            self.age = "Aged " + str(minutes[0]) + " minutes " + str(minutes[1]) +" seconds"

def roi_test(roi_test, bubble):
    if roi_test:
        #print("Do servo stuff here")
        if not bubble.first_run:
            bubble.first_run = True
            bubble.death()
            return bubble
        return bubble
    else:
        #print("Bubble still visible")
        if bubble.first_run:
            bubble.first_run = False
            bubble.born()
            return bubble
        return bubble

def draw_text(frame, bubble_life):
    cv2.putText(frame, bubble_life.born_text,
                (10, 30), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255))
    cv2.putText(frame, bubble_life.death_text,
                (10, 60), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255))
    cv2.putText(frame, bubble_life.age,
                (10, 90), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255))

def thread_handler(source=0):
    video_getter = VideoGet(source).start()
    video_shower = VideoShow(video_getter.frame).start()
    rgb_test = RgbTest(video_getter.frame).start()
    bubble_life = LifeCycle()

    while True:
        if video_getter.stopped or video_shower.stopped:
            video_shower.stop()
            video_getter.stop()
            rgb_test.stop()
            break

        frame = video_getter.frame
        rgb_test.frame = frame
        bubble_life = roi_test(rgb_test.roi_test, bubble_life)
        draw_text(frame, bubble_life)
        if bubble_life.dead:
            bubble_life.delay()
        video_shower.frame = frame

def main():
    thread_handler(0)

if __name__ == "__main__":
    main()


from math import log2, sqrt

import tensorflow as tf
from tensorflow.keras import Model, Sequential
from tensorflow.keras.layers import Layer, Conv2D, ZeroPadding2D, Embedding, Conv2DTranspose, LayerNormalization
from tensorflow.keras.utils import normalize

from einops import rearrange
from dalle_tensorflow.utils import exists, is_empty, masked_mean, top_k, gumbel_softmax
from dalle_tensorflow.layers import Linear
from dalle_tensorflow.transformer import Transformer
from dalle_tensorflow.axial_positional_embedding import AxialPositionalEmbedding

class ResBlock(Layer):
    def __init__(self, filters):
        super(ResBlock, self).__init__()
        self.net = Sequential([
            ZeroPadding2D(padding=(1, 1)),
            Conv2D(filters, 3, padding='valid', activation='relu'),
            ZeroPadding2D(padding=(1, 1)),
            Conv2D(filters, 3, padding='valid', activation='relu'),
            Conv2D(filters, 1)
        ])

    def call(self, x):
        return self.net(x) + x

class DiscreteVAE(Model):
    def __init__(self, image_size=256, num_tokens=512, codebook_dim=512, num_layers=3, num_resblocks=0, hidden_dim=64,
                 channels=3, temperature=0.9, straight_through=False):
        super(DiscreteVAE, self).__init__()
        assert log2(image_size).is_integer(), 'Image size must be a power of 2.'
        assert num_layers >= 1, 'Number of layers must at least 1.'

        self.image_size = image_size
        self.num_tokens = num_tokens
        self.num_layers = num_layers
        self.temperature = temperature
        self.straight_through = straight_through
        self.codebook = Embedding(num_tokens, codebook_dim)

        self.codebook.build([None, self.num_tokens])

        encode_channels = [hidden_dim] * num_layers
        decode_channels = list(reversed(encode_channels))

        encode_channels = [channels, *encode_channels]

        decode_initial_channels = codebook_dim if not num_resblocks > 0 else decode_channels[0]
        decode_channels = [decode_initial_channels, *decode_channels]

        encode_channels_io, decode_channels_io = map(
            lambda tensor: list(zip(tensor[:-1], tensor[1:])), (encode_channels, decode_channels))

        encode_layers = []
        decode_layers = []

        for (encode_in, encode_out), (decode_in, decode_out) in zip(encode_channels_io, decode_channels_io):
            encode_layers.append(Sequential([
                ZeroPadding2D(padding=(1, 1)),
                Conv2D(encode_out, 4, strides=(2, 2), padding='valid', activation='relu')
            ]))
            decode_layers.append(Sequential([
                Conv2DTranspose(decode_out, 4, strides=(2, 2), padding='same', activation='relu'),
            ]))

        for _ in range(num_resblocks):
            decode_layers.insert(0, ResBlock(decode_channels[1]))
            encode_layers.append(ResBlock(encode_channels[-1]))

        if num_resblocks:
            decode_layers.insert(0, Conv2D(decode_channels[1], 1))

        encode_layers.append(Conv2D(num_tokens, 1))
        decode_layers.append(Conv2D(channels, 1))

        self.encoder = Sequential(encode_layers)
        self.decoder = Sequential(decode_layers)

    def get_codebook_indices(self, images):
        logits = tf.stop_gradient(self.call(images, return_logits=True))
        logits = tf.math.argmax(logits, axis=-1)
        codebook_indices = tf.reshape(logits, [-1, tf.reduce_prod(logits.shape[1:])])
        return codebook_indices

    def decode(self, image_sequence):
        image_embeddings = self.codebook(image_sequence)
        b, n, d = image_embeddings.shape
        h = w = int(sqrt(n))

        image_embeddings = rearrange(image_embeddings, 'b (h w) d -> b h w d', h=h, w=w)
        images = self.decoder(image_embeddings)
        return images

    def call(self, image, return_recon_loss=False, return_logits=False):
        logits = self.encoder(image)

        if return_logits:
            # Return logits for getting hard image indices for DALL-E training
            return logits

        soft_one_hot = gumbel_softmax(logits=logits, temperature=self.temperature, axis=-1, hard=self.straight_through)

        codebook_weights = tf.convert_to_tensor(self.codebook.get_weights())
        codebook_weights = tf.squeeze(input=codebook_weights, axis=0)
        sampled = tf.einsum('b h w n, n d -> b h w d', soft_one_hot, codebook_weights)
        out = self.decoder(sampled)

        if not return_recon_loss:
            return out
        loss = tf.compat.v1.losses.mean_squared_error(image, out)
        return loss

class CLIP(Layer):
    def __init__(self, *, text_dim=512, image_dim=512, latent_dim=512, num_text_tokens=10000, text_encode_depth=6,
                 text_sequence_len=256, text_heads=8, num_visual_tokens=512, visual_encode_depth=6, visual_heads=8,
                 visual_image_size=256, visual_patch_size=32, channels=3):
        super(CLIP, self).__init__()
        self.text_embedding = Embedding(num_text_tokens, text_dim)
        self.text_pos_embedding = Embedding(text_sequence_len, text_dim)
        self.text_transformer = Transformer(input_dim=text_dim, depth=text_encode_depth, sequence_len=text_sequence_len,
                                            causal=False, heads=text_heads)
        self.to_text_latent = Linear(units=latent_dim, input_dim=text_dim, bias=False)

        assert visual_image_size % visual_patch_size == 0, 'Image dimensions must be divisible by the patch size.'
        num_patches = (visual_image_size // visual_patch_size) ** 2
        patch_dim = channels * visual_patch_size ** 2

        self.visual_patch_size = visual_patch_size
        self.to_visual_embedding = Linear(units=image_dim, input_dim=patch_dim)
        self.visual_pos_embedding = Embedding(num_patches, image_dim)
        self.visual_transformer = Transformer(input_dim=image_dim, depth=visual_encode_depth, sequence_len=num_patches,
                                              causal=False, heads=visual_heads)
        self.to_visual_latent = Linear(latent_dim, image_dim, bias=False)

        self.temperature = tf.Variable(1.)

    def call(self, text, image, text_mask=None, return_loss=False):
        b, p = text.shape[0], self.visual_patch_size

        text_embeddings = self.text_embedding(text)
        text_embeddings += self.text_pos_embedding(tf.range(text.shape[1]))

        image_patches = rearrange(image, 'b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1=p, p2=p)
        image_embeddings = self.to_visual_embedding(image_patches)
        image_embeddings += self.visual_pos_embedding(tf.range(image_embeddings.shape[1]))

        encode_text = self.text_transformer(text_embeddings, mask=text_mask)
        encode_image = self.visual_transformer(image_embeddings)

        if exists(text_mask):
            text_latents = masked_mean(input_tensor=encode_text, mask=text_mask, axis=1)
        else:
            text_latents = tf.math.reduce_mean(input_tensor=encode_text, axis=1)

        image_latents = tf.math.reduce_mean(input_tensor=encode_image, axis=1)

        text_latents = self.to_text_latent(text_latents)
        image_latents = self.to_visual_latent(image_latents)

        text_latents, image_latents = map(lambda tensor: normalize(tensor, axis=-1, order=2), (text_latents, image_latents))
        temp = tf.math.exp(self.temperature)

        if not return_loss:
            sim = tf.einsum('n d, n d -> n', text_latents, image_latents) * temp
            return sim

        sim = tf.einsum('i d, j d -> i j', text_latents, image_latents) * temp
        labels = tf.range(b)
        loss = (tf.nn.softmax_cross_entropy_with_logits(labels, sim) +
                tf.nn.softmax_cross_entropy_with_logits(tf.transpose(labels), sim)) / 2
        return loss

class DALLE(Model):
    def __init__(self, *, dim, vae, num_text_tokens=10000, text_sequence_len=256, depth, heads=8, dim_head=64,
                 reversible=False, attn_dropout=0.0, ff_dropout=0.0, noncausal_attn_len=0, ignore_index=-100):
        super(DALLE, self).__init__()
        assert isinstance(vae, DiscreteVAE), 'VAE must be an instance of DiscreteVAE.'
        vae.trainable = False   # `Weights for model %s have not yet been created.` would be raised otherwise
        image_size = vae.image_size
        num_image_tokens = vae.num_tokens
        image_sequence_len = (vae.image_size // (2 ** vae.num_layers)) ** 2

        self.text_embedding = Embedding(num_text_tokens, dim)
        self.image_embedding = Embedding(num_image_tokens, dim)

        self.text_pos_embedding = Embedding(text_sequence_len + 1, dim)     # +1 for <BOS>
        self.image_pos_embedding = AxialPositionalEmbedding(dim=dim, axial_shape=(image_size, image_size))

        self.num_text_tokens = num_text_tokens  # For offsetting logits index and calculating cross entropy loss
        self.num_image_tokens = num_image_tokens
        total_tokens = num_text_tokens + num_image_tokens
        self.total_tokens = total_tokens

        self.text_sequence_len = text_sequence_len
        self.image_sequence_len = image_sequence_len
        total_sequence_len = text_sequence_len + image_sequence_len
        self.total_sequence_len = total_sequence_len

        self.noncausal_attn_len = noncausal_attn_len

        self.vae = vae
        if exists(self.vae):
            self.vae = vae
            self.image_embedding = vae.codebook

        self.transformer = Transformer(input_dim=dim, depth=depth, sequence_len=total_sequence_len,
                                       reversible=reversible, causal=True, heads=heads, dim_head=dim_head,
                                       attn_dropout=attn_dropout, ff_dropout=ff_dropout,
                                       noncausal_attn_len=noncausal_attn_len + 1)

        self.to_logits = Sequential([
            LayerNormalization(),
            Linear(units=self.total_tokens, input_dim=dim)
        ])

        sequence_range = tf.range(total_sequence_len)
        logits_range = tf.range(total_tokens)

        sequence_range = rearrange(sequence_range, 'n -> () n ()')
        logits_range = rearrange(logits_range, 'd -> () () d')

        self.logits_mask = tf.Variable(initial_value=(
                ((sequence_range >= text_sequence_len) & (logits_range < num_text_tokens)) |
                ((sequence_range < text_sequence_len) & (logits_range >= num_text_tokens))
        ), trainable=False, name='logits_mask')

        self.ignore_index = ignore_index

    def generate_images(self, text, *, clip=None, mask=None, filter_threshold=0.8, temperature=1):
        vae, text_sequence_len, image_sequence_len, num_text_tokens = \
            self.vae, self.text_sequence_len, self.image_sequence_len, self.num_text_tokens
        total_sequence_len = text_sequence_len + image_sequence_len

        if tf.rank(text) < 2:
            text = tf.expand_dims(input=text, axis=0)
        if exists(mask) and tf.rank(mask) < 2:
            mask = tf.expand_dims(input=mask, axis=0)

        out = text

        for cur_len in range(text.shape[1], total_sequence_len):
            is_image = cur_len >= text_sequence_len

            text, image = out[:, :text_sequence_len], out[:, text_sequence_len:]
            logits = tf.stop_gradient(self(text, image, mask=mask)[:, -1, :])
            filtered_logits = top_k(logits, threshold=filter_threshold)
            probs = tf.nn.softmax(logits=filtered_logits / temperature, axis=-1)
            sample = tf.random.categorical(logits=tf.math.log(probs), num_samples=1)
            # Offset sampled token if it is an image token, since logit space is composed of text and then image tokens
            sample -= num_text_tokens if is_image else 0
            out = tf.concat(values=[out, sample], axis=-1)

            if out.shape[1] <= text_sequence_len:
                mask = tf.pad(tensor=mask, paddings=[[0, 0], [0, 1]], mode='CONSTANT', constant_values=True)

        text_sequence = out[:, :text_sequence_len]

        image_sequence = out[:, -image_sequence_len:]
        images = vae.decode(image_sequence)

        if exists(clip):
            scores = clip(text=text_sequence, image=images, return_loss=False)
            return images, scores

        return images

    def call(self, text, image=None, mask=None, return_loss=False):
        ignore_index, total_sequence_len = self.ignore_index, self.total_sequence_len

        # Use padding 1 as <BOS>
        text = tf.pad(tensor=text, paddings=[[0, 0], [1, 0]], mode="CONSTANT", constant_values=1)

        if exists(mask):
            mask = tf.pad(tensor=mask, paddings=[[0, 0], [1, 0]], mode="CONSTANT", constant_values=True)

        tokens = self.text_embedding(text)
        tokens += self.text_pos_embedding(tf.range(text.shape[1]))

        sequence_len = tokens.shape[1]

        if exists(image) and not is_empty(image):
            is_raw_image = len(image.shape) == 4
            if is_raw_image:
                image = self.vae.get_codebook_indices(image)

            image_len = image.shape[1]
            image_embeddings = self.image_embedding(image)
            image_embeddings += self.image_pos_embedding(image_embeddings)
            tokens = tf.concat([tokens, image_embeddings], axis=1)
            sequence_len += image_len
            if exists(mask):
                mask = tf.pad(tensor=mask, paddings=[[0, 0], [0, image_embeddings.shape[1]]], mode='CONSTANT',
                              constant_values=True)

        # When training, if the length exceeds the total text + image length
        # Remove the last token, since it needs not to be trained
        if tokens.shape[1] > total_sequence_len:
            sequence_len -= 1
            tokens = tokens[:, :-1]

            if exists(mask):
                mask = mask[:, :-1]
        out = self.transformer(tokens, mask=mask)
        logits = self.to_logits(out)

        # Mask logits to make sure text predicts text (except last token), and image predicts image
        logits_mask = self.logits_mask[:, :sequence_len]
        max_negative_value = -tf.experimental.numpy.finfo(logits.dtype).max
        logits = tf.where(logits_mask, max_negative_value, logits)

        if not return_loss:
            return logits

        assert exists(image), 'When training, image must be supplied.'
        noncausal_attn_len = self.noncausal_attn_len
        offsetted_image = image + self.num_text_tokens
        offsetted_image = tf.cast(offsetted_image, dtype=text.dtype)
        labels = tf.concat(values=[text[:, 1:], offsetted_image], axis=1)

        if noncausal_attn_len:
            sequence_range = tf.range(sequence_len)
            noncausal_attn_mask = sequence_range < noncausal_attn_len
            noncausal_attn_mask = rearrange(noncausal_attn_mask, 'n -> () n')
            labels = tf.where(noncausal_attn_mask, ignore_index, labels)

        loss = tf.nn.sparse_softmax_cross_entropy_with_logits(labels, logits)
        return loss


# I have created this file
from django.http import HttpResponse
from django.shortcuts import render
def index(request):
    return HttpResponse('''
gopal jha is here

Learning 1

Learn boostrap

    ''')
def learning1(request):
    # return HttpResponse('''
gopal jha is here

hello everyone here
 gopajha
    #
vitality

    # ''');

     #render are use for trnasfer the data from main python to html file on other side we use {{}} this symbol
     #rendor have three parameter: 1. request 2. path 3. variable

    a={'name1':"gopal",'name2':"ravi"}
    return render(request,'index.html',a);

def removepunc(request):

    #get data from html page by using request.GET.get() function in python
    #post data from html page by using request.POST.get() function in python when ever we use post we have to write {% csrf_token %} on form section on html

    t1=request.POST.get('text','default')
    t2=request.POST.get('removepunch','off')
    t3=request.POST.get('upperCase','off')
    t4=request.POST.get('nlr','off')
    print(t1);
    out=t1
    if t2=="on":
        specil_key=["!","@","#","$","%","^","&","*","(",")","_","+","{","}",":","<",">",">","<","?","|",",",".",";","'","[","]","/","-","=",]
        result=""
        for i in t1:
            if i not in specil_key:
                result+=i;
        out=result;

    if(t3=="on"):
        out=out.upper()
    if(t4=="on"):
        result=""
        for i in out:
            if(i !="\n"):
                result+=i;
            else:
                break;
        out=result;
    if((t2=="off") and (t3=="off") and t4=="off"):
        test1={
        "word":t1,
        "result":"Select checkbox"
        }
        return render(request,'removePunch.html',test1)
    test1={
        "word":t1,
        "result":out
        }
    return render(request,'removePunch.html',test1)

def contact(request):
    return HttpResponse('''8745977703
    back

    ''');

#start boostrap
def boostrap(request):
    return render(request,'learn_boostrap.html');
# end boostrap


"""datetime_2_date

Revision ID: f1fda4d52e24
Revises: b3ee7d1a3f0a
Create Date: 2022-03-28 10:30:29.498461

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = 'f1fda4d52e24'
down_revision = 'b3ee7d1a3f0a'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('customers', 'date_of_birth')
    op.drop_column('price_list', 'date_of_end')
    op.drop_column('review', 'date_of_creation_payment')
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('review', sa.Column('date_of_creation_payment', postgresql.TIMESTAMP(), autoincrement=False, nullable=True))
    op.add_column('price_list', sa.Column('date_of_end', postgresql.TIMESTAMP(), autoincrement=False, nullable=True))
    op.add_column('customers', sa.Column('date_of_birth', postgresql.TIMESTAMP(), autoincrement=False, nullable=False))
    # ### end Alembic commands ###


from typing import List, Optional
from pydantic import BaseModel

class PlatformBaseSchema(BaseModel):
    id: Optional[int]
    name: str
    platform_games: List[BaseModel] = list()

    class Config:
        orm_mode = True
        allow_population_by_field_name = True
        arbitrary_types_allowed = True

    def __eq__(self, other):
        if isinstance(self, type(other)):
            return self.name == other.name
        return False

class ListPlatformBaseResponse(BaseModel):
    status: str
    results: int
    platforms = List[PlatformBaseSchema]

    class Config:
        orm_mode = True
        allow_population_by_field_name = True
        arbitrary_types_allowed = True


from flask import Flask, jsonify, send_file
from flask_cors import CORS

import db
from ubuntuarchive import get_all_package_lists, get_all_packages_in_list

app = Flask(__name__)
CORS(app)

# /search/<pkg_name>
# /package/<pkg_name>/<version*>/<architecture**>
# /install (json with package id list)
@app.route("/search/<pkg_name>", methods=["GET"])
def find_packages_by_name(pkg_name):
    try:
        return jsonify(db.find_packages_by_name(pkg_name)), 200
    except Exception as e:
        return jsonify({"errormsg": str(e)}), 404

@app.route("/package/<pkg_name>", methods=["GET"])
def get_packages_by_name(pkg_name):
    try:
        return jsonify(db.get_packages_by_name(pkg_name)), 200
    except Exception as e:
        return jsonify({"errormsg": str(e)}), 404

@app.route("/package/<pkg_name>/<pkg_version>", methods=["GET"])
def get_packages_by_name_version(pkg_name, pkg_version):
    try:
        return jsonify(db.get_packages_by_name_version(pkg_name, pkg_version)), 200
    except Exception as e:
        return jsonify({"errormsg": str(e)}), 404

@app.route("/package/<pkg_name>/<pkg_version>/<pkg_architecture>", methods=["GET"])
def get_package_by_name_version_arch(pkg_name, pkg_version, pkg_architecture):
    try:
        return jsonify(db.get_package_by_name_version_arch(pkg_name, pkg_version, pkg_architecture)), 200
    except Exception as e:
        return jsonify({"errormsg": str(e)}), 404

@app.route("/package_id/<pkg_id>", methods=["GET"])
def get_package_by_id(pkg_id):
    try:
        return jsonify(db.get_package_by_id(pkg_id)), 200
    except Exception as e:
        return jsonify({"errormsg": str(e)}), 404

@app.route("/package/<pkg_name>/<pkg_version>/<pkg_architecture>/download", methods=["GET"])
def download_package_by_name_version_arch(pkg_name, pkg_version, pkg_architecture):
    try:
        return send_file(
            db.download_package_by_name_version_arch(pkg_name, pkg_version, pkg_architecture),
            "application/vnd.debian.binary-package",
            as_attachment=True,
            attachment_filename="{}_{}_{}.deb".format(pkg_name, pkg_version, pkg_architecture)
        ), 200
    except Exception as e:
        return jsonify({"errormsg": str(e)}), 404

@app.route("/rebuild_db", methods=["GET"])
def rebuild_db():
    try:
        pkg_lists = get_all_package_lists()
        for pkg_list in pkg_lists:
            packages = get_all_packages_in_list(pkg_list)
            db.update_packages_database(packages)
    except Exception as e:
        return jsonify({"errormsg": str(e)}), 500
    return jsonify({}), 200

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5122)

# http://localhost:5000/search/nano
# http://localhost:5000/package/nano
# http://localhost:5000/package/nano/2.9.8-1
# http://localhost:5000/package/nano/2.9.8-1/amd64
# http://localhost:5000/package/nano/2.9.8-1/amd64/download
# http://localhost:5000/install


import json

def ask_for_input():
	# symptomsRaw = input("Please enter your symptoms separated by a comma and space: ")
	# symptomList = symptomsRaw.split(", ")
	filepath = "Symptoms.json"
	with open(filepath) as fp:
		symptomData = json.load(fp)
		symptomList = symptomData["symptoms"]
	return symptomList	#list of symptoms from user

def retrieve_ontology():
	filepath = "DOSFinal.json"
	with open(filepath) as fp:
		ontologyData = json.load(fp)
	return ontologyData	#ontology JSON containing keywords

def search_for_candidates(ontologyData, symptomList):
	candidateList = []
	for disease in ontologyData["diseases"]:
		totalKeywordCounter = len(disease["name"].split())
		diagnosis = {}
		totalRecorded = False
		unmatchedKeywords = disease["keywords"]
		for symptom in symptomList:
			keywordFoundCounter = 0	#take record of number of matches for each symptom
			nameIsMatch = disease["name"].lower().find(symptom)
			if (nameIsMatch > -1):	#check symptom against disease name
				keywordFoundCounter += 1
				if ("name" not in diagnosis):	#initialize dictionary entry
					diagnosis["name"] = disease["name"]
					diagnosis["search terms"] = []

			if (len(disease["keywords"]) > 0):	#only run code on ontology entries with keywords
				if (totalRecorded == False): #prevents duplication of number of total keywords for each symptom in symptomList
					totalKeywordCounter += len(disease["keywords"])
					totalRecorded = True
				for keyword in disease["keywords"]:
					keywordIsMatch = keyword.lower().find(symptom)
					if (keywordIsMatch > -1):	#check symptom against keywords
						unmatchedKeywords = list(filter(lambda a: a != keyword, unmatchedKeywords))
						keywordFoundCounter += 1
						if ("name" not in diagnosis):	#initialize dictionary entry
							diagnosis["name"] = disease["name"]
							diagnosis["search terms"] = []

			if keywordFoundCounter != 0:	#only run code if the ontology entry contained the keyword
				diagnosis["search terms"].append({"# of '" + symptom + "' found": keywordFoundCounter})
		if (bool(diagnosis) == True):	#check diagnosis is not empty because there was no match
			diagnosis["unmatched keywords"] = unmatchedKeywords
			diagnosis["total # of keywords"] = totalKeywordCounter #have to divide by number of symptoms because total keywords amount is duplicated for each loop of a symptom
			candidateList.append(diagnosis)
	return candidateList	#candidates have any of the symptoms but may not have all the symptoms the user provided

def filter_candidates(candidateList, symptomList):
	diagnosesList = []
	for diagnosis in candidateList:
		if (len(diagnosis["search terms"]) == len(symptomList)):	#filter only for candidates that have all the user-provided symptoms
			totalSearchTermFoundCounter = 0	#find sum of all keywords found for ranking purposes
			for term in diagnosis["search terms"]:	#check each "# of __ found" entries
				for key in term:
					totalSearchTermFoundCounter += term[key]	#add number of each symptom found to total counter
			diagnosis["sum of search terms found"] = totalSearchTermFoundCounter
			diagnosesList.append(diagnosis)
	return diagnosesList

def create_JSON(symptomList, rankedDiagnosesList):
	data = {}
	data["patient"] = {"symptoms": symptomList,
					   "diagnoses": rankedDiagnosesList
					  }
	return data

def write_to_json(data):
	filename = "Diagnosis.json"
	with open(filename, "w", encoding = "utf-8") as file:
		json.dump(data, file, indent = 4)

symptomList = ask_for_input()
ontologyData = retrieve_ontology()
candidateList = search_for_candidates(ontologyData, symptomList);
diagnosesList = filter_candidates(candidateList, symptomList)
rankedDiagnosesList = sorted(diagnosesList, key = lambda x: list(x.values())[2], reverse = True)	#sort diagnosesList according to the 2nd index entry which is the total # of keywords
data = create_JSON(symptomList, rankedDiagnosesList)
write_to_json(data)


from __future__ import print_function

# from multiprocessing import Process
# import os, sys

# def f(name):
#     print('{0:<15}'.format('hello '+name), 'module name:', '{0:<15}'.format(__name__), 'parent process:', '{0:<15}'.format(os.getppid()), 'process id:', '{0:<15}'.format(os.getpid()))

# if __name__ == '__main__':
#     for num in range(6):
#         p = Process(target=f, args=('bob '+str(num),))
#         p.start()
#         p.join()
# sys.exit()

import time
from multiprocessing import Process, Lock
def print_with_lock(loc, i):
    loc.acquire()
    try:
        print('hello world ', i)
        time.sleep(1)
    finally:
        loc.release()
if __name__ == '__main__':
    lock = Lock()
    for num in range(6):
        p = Process(target=print_with_lock, args=(lock, num))
        p.start()
        p.join()

# from StringIO import StringIO
# from multiprocessing import Process, Queue
# import sys, time
# # Proxy classes that both write to and capture strings
# # sent to stdout or stderr, respectively.
# class TeeOut(StringIO):
#     def write(self, s):
#         StringIO.write(self, s)
#         sys.__stdout__.write(s)
# class TeeErr(StringIO):
#     def write(self, s):
#         StringIO.write(self, s)
#         sys.__stderr__.write(s)
# class Parent(object):
#     def run(self):
#         # Start child process.
#         queue = Queue()

#         for i in range(3):
#             child = Process(target=self.spawn, args=(queue,))
#             child.start()
#             child.join()
#         # Do someting with out and err...
#         out = queue.get()
#         err = queue.get()
#     def spawn(self, queue):
#         # Save everything that would otherwise go to stdout.
#         out = sys.stdout = TeeOut()
#         err = sys.stderr = TeeErr()

#         try:
#             # Do something...
#             sys.stdout.write('out 1\n')
#             sys.stderr.write('error 1\n')
#         finally:
#             # Restore stdout, stderr and send their contents.
#             sys.stdout = sys.__stdout__
#             sys.stderr = sys.__stderr__
#             queue.put(out.getvalue())
#             queue.put(err.getvalue())
# if __name__ == '__main__':
#     Parent().run()


def readit_all(filename = "penguins.csv"):

  with open(filename, 'r') as file:
    mylist = file.read().rstrip().split("\n")

  keys = mylist.pop(0).split(",")
  data = []
  for line in mylist:
    values = line.split(",")
    datum = {keys[i]: value for i, value in enumerate(values)}
    data.append(datum)

  return data

import matplotlib.pyplot as plt

data = readit_all()

x_label = "bill_length_mm"
y_label = "bill_depth_mm"

for datum in data:
  if datum[x_label] == "NA" or datum[y_label] == "NA":
    continue
  plt.scatter(float(datum[x_label]), float(datum[y_label]), c="steelblue")

data[0]
plt.show()

z_label = "species"
species = set([d[z_label] for d in data])
colormap = {s: ['tab:blue', 'tab:orange', 'tab:green'][i] for i,s in enumerate(species)}

for d in data:
    if d[x_label] == "NA" or d[y_label] == "NA":
        continue

    color = colormap[d[z_label]]
    plt.scatter(float(d[x_label]), float(d[y_label]), color=color)

plt.xlabel(x_label)
plt.ylabel(y_label)
plt.show()

def process(data, x = "bill_length_mm", y = "flipper_length_mm", z = "species"):
    bad_count = 0
    X = []
    Y = []
    Z = []
    for d in data:

      if "NA" in [d[x], d[y], d[z]]:
          bad_count += 1
          print("Skipping NA --", bad_count, "lines skipped")
          continue

      X.append(float(d[x]))
      Y.append(float(d[y]))
      Z.append(d[z])

    return X, Y, Z

X, Y, Z = process(data)

for s in species:
  X_subset=[x_sub for x_sub,z_sub in zip(X,Z) if z_sub==s]
  Y_subset=[y_sub for y_sub,z_sub in zip(Y,Z) if z_sub==s]

  X_subset = [d for i, d in enumerate(X) if s == Z[i]]
  Y_subset = [d for i, d in enumerate(Y) if s == Z[i]]

  plt.scatter(X_subset, Y_subset, label=s)

plt.legend()
plt.show()


from multiprocessing import Process

from bs4 import BeautifulSoup
from bs4.element import Comment

import setproctitle

class Logger:
    def __init__(self, n, manager):
        self.queue = manager.Queue()
        self.n = n
        self.start()

    def start(self):
        Process(target=self.worker).start()

    def worker(self):
        setproctitle.setproctitle('python logger')

        count = 0
        while True:
            msg = self.queue.get()

            if msg == "shutdown" or count > self.n:
                return

            self.print_message(*msg)
            count += 1

    @staticmethod
    def tag_visible(element):
        if element.parent.name in [
            "style",
            "script",
            "head",
            "title",
            "meta",
            "[document]",
        ]:
            return False
        if isinstance(element, Comment):
            return False
        return True

    def add_message(self, html, url, timestamp):
        self.queue.put((html, url, timestamp))

    def print_message(self, html, url, timestamp):
        soup = BeautifulSoup(html, "html.parser")
        texts = soup.find_all(text=True)
        visible_texts = filter(Logger.tag_visible, texts)
        visible_text = " ".join(t.strip() for t in visible_texts)
        title = soup.title.string if soup.title else ""
        print(
            f"{{ \"URL\": \"{url}\",\n  \"Title\": \"{title}\",\n  \"Text\": \"{' '.join(visible_text.split()[:20])}\",\n  \"Timestamp\": {timestamp} }}"
        )

    def shutdown(self):
        self.queue.put("shutdown")