import sys
import time
from uspp import *

from crcnetd._utils.ccsd_common import *
from crcnetd._utils.ccsd_log import *
from crcnetd._utils.ccsd_clientserver import registerPage, registerRecurring
from crcnetd._utils.ccsd_config import config_get
from crcnetd._utils.ccsd_events import registerEvent, triggerEvent

from ccs_monitor_web import registerMenuItem, HTable, returnPage, \
    returnErrorPage, MENU_TOP, MENU_GROUP_GENERAL
import  ccs_monitor_snmp as snmp

registerDynamicOID = snmp.registerDynamicOID

class ccs_solar_error(ccsd_error):
    pass

ccs_mod_type = CCSD_CLIENT

DEFAULT_TRISTAR_PORT = "/dev/ttyS0"
DEFAULT_AV_MAX = 24
DEFAULT_CI_MAX = 45

# Implement the Tristar Solar portion of the CRCnet-MIB
CRCNET_TRISTAR45_MIB = (1,3,6,1,4,1,15120,1,2,1)
# All wireless interface properties
CRCNET_TRISTAR45_PROPS = range(1,26)

# CRC tables for calculating CRC's over the serial packets
CRCtablehi = (
0x0,0xc0,0xc1,0x1,0xc3,0x3,0x2,0xc2,0xc6,0x6,0x7,0xc7,0x5,0xc5,0xc4,0x4,
0xcc,0xc,0xd,0xcd,0xf,0xcf,0xce,0xe,0xa,0xca,0xcb,0xb,0xc9,0x9,0x8,0xc8,
0xd8,0x18,0x19,0xd9,0x1b,0xdb,0xda,0x1a,0x1e,0xde,0xdf,0x1f,0xdd,0x1d,0x1c,0xdc,
0x14,0xd4,0xd5,0x15,0xd7,0x17,0x16,0xd6,0xd2,0x12,0x13,0xd3,0x11,0xd1,0xd0,0x10,
0xf0,0x30,0x31,0xf1,0x33,0xf3,0xf2,0x32,0x36,0xf6,0xf7,0x37,0xf5,0x35,0x34,0xf4,
0x3c,0xfc,0xfd,0x3d,0xff,0x3f,0x3e,0xfe,0xfa,0x3a,0x3b,0xfb,0x39,0xf9,0xf8,0x38,
0x28,0xe8,0xe9,0x29,0xeb,0x2b,0x2a,0xea,0xee,0x2e,0x2f,0xef,0x2d,0xed,0xec,0x2c,
0xe4,0x24,0x25,0xe5,0x27,0xe7,0xe6,0x26,0x22,0xe2,0xe3,0x23,0xe1,0x21,0x20,0xe0,
0xa0,0x60,0x61,0xa1,0x63,0xa3,0xa2,0x62,0x66,0xa6,0xa7,0x67,0xa5,0x65,0x64,0xa4,
0x6c,0xac,0xad,0x6d,0xaf,0x6f,0x6e,0xae,0xaa,0x6a,0x6b,0xab,0x69,0xa9,0xa8,0x68,
0x78,0xb8,0xb9,0x79,0xbb,0x7b,0x7a,0xba,0xbe,0x7e,0x7f,0xbf,0x7d,0xbd,0xbc,0x7c,
0xb4,0x74,0x75,0xb5,0x77,0xb7,0xb6,0x76,0x72,0xb2,0xb3,0x73,0xb1,0x71,0x70,0xb0,
0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,
0x9c,0x5c,0x5d,0x9d,0x5f,0x9f,0x9e,0x5e,0x5a,0x9a,0x9b,0x5b,0x99,0x59,0x58,0x98,
0x88,0x48,0x49,0x89,0x4b,0x8b,0x8a,0x4a,0x4e,0x8e,0x8f,0x4f,0x8d,0x4d,0x4c,0x8c,
0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x80
)
CRCtablelo = (
0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,
0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,
0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,
0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,
0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,
0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,
0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,
0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,
0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,
0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,
0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,
0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,
0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,
0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,
0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x40,0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,
0x0,0xc1,0x81,0x40,0x1,0xc0,0x80,0x41,0x1,0xc0,0x80,0x41,0x0,0xc1,0x81,0x81
)

# Tristar commands
TS_BATT_V_F         = 0x0008    # Battery voltage, filtered (Tau=2.5s)
TS_BATTSENSE_V_F    = 0x0009    # Battery sense voltage, filtered (Tau=2.5s)
TS_ARRAY_V_F        = 0x000A    # Array/Load voltage, filtered (Tau=2.5s)
TS_CHARGE_I_F       = 0x000B    # Battery charge current, filtered (Tau=2.5s)
TS_LOAD_I_F         = 0x000C    # Load current, filtered (Tau=2.5s)
TS_BATT_V_SF        = 0x000D    # Battery voltage, slow filter (Tau=25s)
TS_HSTEMP_DEG       = 0x000E    # Heatsink temperature
TS_BATTEMP_DEG      = 0x000F    # Battery temperature
TS_REF_V            = 0x0010    # Charge regulator reference voltage
TS_AMPHR_AH_HI      = 0x0011    # Ah resetable, HI word
TS_AMPHR_AH_LO      = 0x0012    # Ah resetable, LO word
TS_TOTALAMPHR_AH_HI = 0x0013    # Ah total, HI word
TS_TOTALAMPHR_AH_LO = 0x0014    # Ah total, LO word
TS_HRMETER_HR_HI    = 0x0015    # Hourmeter, HI word
TS_HRMETER_HR_LO    = 0x0016    # Hourmeter, LO word
TS_ALARMBITS_B_LO   = 0x0017    # Alarm bitfield - low bits
TS_FAULTBITS_B      = 0x0018    # Fault bitfield
TS_DIPSWITCH_B      = 0x0019    # Dip switch settings at power on
TS_CONTROLMODE      = 0x001A    # Control mode (0=charge, 1=load, 2=diversion)
TS_CONTROLSTATE     = 0x001B    # Control state
TS_PWMDUT           = 0x001C    # PWM Duty Cycle - 0-255
TS_ALARMBITS_B_HI   = 0x001D    # Alarm bitfield (continued from 0x0017)

# EEPROM registers for the tristar
TS_REGVAT25_V       = 0xE000    # Regulation voltage @ 25 deg C
TS_FLVAT25_V        = 0xE001    # Float voltage @ 25 deg C
TS_TBEFOREFL_S      = 0xE002    # Time before entering float
TS_TBEFOREFLLB_S    = 0xE003    # Time before entering float due to low battery
TS_LBVTRIGFL_V      = 0xE004    # Voltage that triggers low battery float time
TS_FLCANCEL_V       = 0xE005    # Voltage that cancels float
TS_EQUVAT25_V       = 0xE006    # Equalize voltage @ 25 deg C
TS_TBETWEENEQU_D    = 0xE007    # Days between eq cycles
TS_EQUTLIMIT_S      = 0xE008    # Equalize time limit above Vreg
TS_EQUTLIMITATVEQ_S = 0xE009    # Equalize time limit at Veq
TS_EVTEMPCOMP       = 0xE00A    # EV_tempcomp LSB only (note -(2-16) scaling)
TS_HVDCAT25         = 0xE00B    # High Voltage Disconnect @ 25 deg C
TS_HVRC             = 0xE00C    # High Voltage Reconnect
TS_DSLEQU           = 0xE00D    # Days since last equalize
TS_CUMTAT100        = 0xE00E    # Cum. time at 100% duty cycle, exit float
TS_LVDC             = 0xE00F    # Low Voltage Disconnect
TS_LVRC             = 0xE010    # Low Voltage Reconnect
TS_LHVDC            = 0xE011    # Load High Voltage Disconnect
TS_LHVRC            = 0xE012    # Load High Voltage Reconnect
TS_LVDLCC           = 0xE013    # LVD Load current compensation
TS_LVDWT            = 0xE014    # LVD warning timeout
TS_LTASS            = 0xE015    # Lighting Time after sunset
TS_LTASR            = 0xE016    # Lighting time before sunrise
TS_LIGHTCFG_B       = 0xE017    # Lighting Configuration Bits
TS_NTT_V            = 0xE018    # Night time threshold - Array Voc
TS_MTT_V            = 0xE019    # Morning threshold for timing - Array Voc
TS_MTL_V            = 0xE01A    # Morning threshold for lighting - Array Voc
TS_LEDGGY_V         = 0xE01B    # LED green to green/yellow limit
TS_LEDGYY_V         = 0xE01C    # LED green/yellow to yellow limit
TS_LEDYYR_V         = 0xE01D    # LED yellow to yellow/red limit
TS_LEDYRR_V         = 0xE01E    # LED yellow/red to red limit
TS_MAXTCOMP_DEG     = 0xE01F    # Max battery temp compensation limit deg C
TS_MINTCOMP_DEG     = 0xE020    # Min battery temp compensation limit deg C
TS_SERVID           = 0xE021    # Modbus TriStar server ID
TS_DBBSI_D          = 0xE022    # Days between battery service intervals
TS_DSLBS_D          = 0xE023    # Days since last battery service
TS_PHRMETER_HR_LO   = 0xE024    # Hourmeter - low word
TS_PHRMETER_HR_HI   = 0xE025    # Hourmeter - high word
TS_RESAH_AH_LO      = 0xE026    # Resetable Ah low
TS_RESAH_AH_HI      = 0xE027    # Resetable Ah high
TS_TOTAH_AH_LO      = 0xE028    # Total Ah low byte
TS_TOTAH_AH_HI      = 0xE029    # Total Ah high byte
TS_KWH              = 0xE02A    # Kilowatt hours
TS_MINBV_V          = 0xE02B    # Minimum battery voltage
TS_MAXBV_V          = 0xE02C    # Maximum battery voltage

# Calibration registers for the tristar
TS_SERNUM10         = 0xF000    # Serial number (8 byte ascii string) [1][0]
TS_SERNUM32         = 0xF001    # [3][2]
TS_SERNUM54         = 0xF002    # [5][4]
TS_SERNUM76         = 0xF003    # [7][6]
TS_BVDCALAT48_V     = 0xF004    # Battery voltage divider calib., 48V mode
TS_BVDCALAT1224_V   = 0xF005    # Battery voltage divider calib., 12/24V mode
TS_CHARGEICAL_I     = 0xF006    # Charge current calibration
TS_LOADICAL_I       = 0xF007    # Load current calibration
TS_SENSEVCAL_V      = 0xF008    # Sense voltage calibration
TS_ALVDCAL_V        = 0xF009    # Array/Load voltage divider calibration
TS_HWVER            = 0xF00A    # MSB:H/W Version major,LSB:H/W version minor
TS_CALSTATE         = 0xF00B    # MSB:Calibration state (0x5A is calibrated).
                                # LSB is 0x01 for the TS-60, 0x00 for the TS-45

# Time that the amphours were last reset
amphours_reset = 0
# ID String of the tristar
ts_id = "No Tristar Detected"

##############################################################################
# Utility Functions
##############################################################################
def init_serial():
    """Initialises the serial port and connects to the tristar"""

    portname = config_get("status", "tristar_port", DEFAULT_TRISTAR_PORT)

    # Open the port
    p=[1, 0, 2301, 0, 13, 13]
    tty = SerialPort(portname, timeout=100, speed=9600, mode="232", params=p)

    return tty

def write_serial(fd, bytes):
    """Writes the bytes in the supplied tuple to the serial port"""
    fd.write("".join([chr(a) for a in bytes]))

def read_serial(fd):
    """Returns a tuple containing bytes read from the serial port"""

    bytes = ()

    try:
        while 1:
            b = fd.read()
            bytes += (ord(b),)
    except SerialPortException:
        # Timeout raised
        pass

    return bytes

def calc_crc(bytes):
    """Calculates a CRC checksum over the specified bytes"""
    CRC = 0xFFFF

    for i in bytes:
        CRC^=i
        CRC=((CRC>>8)&0xFF)^CRCtablelo[CRC&0xFF]|(CRCtablehi[CRC&0xFF]<<8)

    return CRC&0xFFFF

def ts_do(w_pdu, exp_rcode, no_crc=False):
    """Queries the tristar with the specified packet and reads the result

    The packet passed to this function should have two spare bytes at the end
    for the checksum to be inserted into.

    The exp_rcode should contain a sequence of expected bytes that must be
    found starting at offset 1 of the returned value for the request to succeed

    Some basic checks are performed on the result, if these pass the entire
    result is passed back for further processing.
    """

    # Calculate the checksum and store in the last two positions
    if not no_crc:
        w_pdu = list(w_pdu)
        i = calc_crc(w_pdu[:-2])
        w_pdu[6] = i&0xFF
        w_pdu[7] = (i&0xFF00)>>8

    # Open a connection to the tristar
    tty = init_serial()

    # Try and read 10 times before giving up
    for i in range(0,10):
        write_serial(tty, w_pdu)
        r = read_serial(tty)
        if len(r) <= 2:
            continue

        # Check that the PDU is the response to the request we made
        if r[0] != w_pdu[0]:
            continue

        # Check the checksum
        k=calc_crc(r[:-2])
        if r[-1]!=((k&0xFF00)>>8) and r[-2]!=(k&0xFF):
            continue

        # Check for explicit error
        if r[1] == 0x84:
            log_error("Bad packet received from Tristar")
            del tty
            return None

        # Check the appropriate codes to ensure that this is
        # the response for the request we made
        i = 1
        for val in exp_rcode:
            if r[i] != val:
                continue
            i+=1

        # All OK
        del tty
        return r

    # Timed out
    del tty
    log_error("Tristar Request Timed Out")
    return None

def ts_readreg(reg):
    """Returns the value of the specified register on the tristar unit"""

    # Setup the request
    w_pdu = [0x01,0x04,(reg&0xFF00)>>8,reg&0xFF,0x00,0x01,0x00,0x00]

    # Send the request
    r = ts_do(w_pdu, (0x04, 0x02))
    if r is None:
        return 0xFFFF

    # Return the result
    return (r[3]<<8)|r[4]

def ts_writecoil(reg, val):
    """Writes a value to the specified "coil" on the Tristar unit"""

    # Setup the request
    w_pdu = [0x01,0x05,(reg&0xFF00)>>8,reg&0xFF,(val&0xFF00)>>8,val&0xFF,
        0x00,0x00]

    # Send the request
    r = ts_do(w_pdu, (0x04, 0x02))
    if r is None:
        return 0xFFFF

    # Return the result
    return (r[3]<<8)|r[4]

def find_tristar():
    """Tries to find a Tristar device on the serial port"""
    global ts_id

    # Setup the request
    tristar_requestID = (0x01,0x2B,0x0E,0x01,0x00,0x70,0x77)

    # Send the request
    r = ts_do(tristar_requestID, (0x2B, 0x0E, 0x01), True)
    if r is None:
        log_error("Could not detect Tristar unit!")
        return False

    # Filter through the data to find the stuff we want
    tptr=8
    matches=0
    id = ""
    for k in range(0,r[7]):
        start = tptr+2
        end = start + r[tptr+1]
        string = "".join([chr(a) for a in r[start:end]])
        if r[tptr]==0x00:
            # Vendor Name
            if string == "Morningstar Corp.":
                matches+=1
                id = string
        elif r[tptr]==0x01:
            # Product Code
            if string == "TS-45" or string == "TS-60":
                matches+=1
                id = "%s %s" % (id, string)
        elif r[tptr]==0x02:
            id = "%s %s" % (id, string)
        # Move on
        tptr += r[tptr+1]+2

    if matches < 2:
        log_error("Could not detect Tristar unit!")
        return False
    else:
        log_info("Detected Solar Controller: %s" % id)
        ts_id = id
        return True

# Helper functions to read and process data from the tristar
def ts_battv():
    d=ts_readreg(TS_BATT_V_F)
    d*=96.667/32768
    return d*1000
def ts_battsensev():
    d=ts_readreg(TS_BATTSENSE_V_F)
    d*=96.667/32768
    return d*1000
def ts_arrayv():
    av_max = portname = config_get("status", "array_v_max", DEFAULT_AV_MAX)
    for i in range(0,2):
        d=ts_readreg(TS_ARRAY_V_F)
        d*=139.15/32768
        if d <= av_max:
            return d*1000
    return 0
def ts_chargei():
    ci_max = portname = config_get("status", "charge_i_max", DEFAULT_CI_MAX)
    for i in range(0,2):
        d=ts_readreg(TS_CHARGE_I_F)
        d*=66.667/32768
        if d <= ci_max:
            return d*1000
    return 0
def ts_loadi():
    d=ts_readreg(TS_LOAD_I_F)
    d*=316.67/32768
    return d*1000
def ts_battvs():
    d=ts_readreg(TS_BATT_V_SF)
    d*=96.667/32768
    return d*1000
def ts_refv():
    d=ts_readreg(TS_REF_V)
    d*=96.667/32768
    return d*1000
def ts_amphours():
    i=ts_readreg(TS_AMPHR_AH_HI)
    i2=ts_readreg(TS_AMPHR_AH_LO)
    i&=0xFFFF
    i<<=16
    i|=(0xFFFF&i2)
    d=i*0.1
    return d*1000
def ts_totalamphours():
    i=ts_readreg(TS_TOTALAMPHR_AH_HI)
    i2=ts_readreg(TS_TOTALAMPHR_AH_LO)
    i&=0xFFFF
    i<<=16
    i|=(0xFFFF&i2)
    d=i*0.1
    return d*1000
def ts_hrmeter():
    i=ts_readreg(TS_HRMETER_HR_HI)
    i2=ts_readreg(TS_HRMETER_HR_LO)
    i&=0xFFFF
    i<<=16
    i|=(0xFFFF&i2)
    d=i*0.1
    return d*1000
def ts_minbv():
    d=ts_readreg(TS_MINBV_V)
    d*=96.667/32768
    return d*1000
def ts_maxbv():
    d=ts_readreg(TS_MAXBV_V)
    d*=96.667/32768
    return d*1000
def ts_pwm():
    d = ts_readreg(TS_PWMDUT)
    if d>230:
        d = 230
    d/=230
    d*=100
    return d*1000
def ts_serial():
    buf = ""
    i=ts_readreg(TS_SERNUM10)
    buf += chr(i&0xFF)
    buf += chr((i>>8)&0xFF)
    i=ts_readreg(TS_SERNUM32)
    buf += chr(i&0xFF)
    buf += chr((i>>8)&0xFF)
    i=ts_readreg(TS_SERNUM54)
    buf += chr(i&0xFF)
    buf += chr((i>>8)&0xFF)
    i=ts_readreg(TS_SERNUM76)
    buf += chr(i&0xFF)
    buf += chr((i>>8)&0xFF)
    return buf
def ts_hwver():
    i=ts_readreg(TS_SERNUM10)
    min = (0xFF&i)
    max = ((i>>8)&0xFF)
    return "%d.%d" % (max,min)
def ts_controlmode_s():
    i = ts_readreg(TS_CONTROLMODE)
    if i == 0:
        return "Charge"
    elif i == 1:
        return "Load"
    elif i == 2:
        return "Diversion"
    else:
        return "Unknown (%d)" % i
def ts_controlstate_s():
    i = ts_readreg(TS_CONTROLSTATE)
    if i == 0:
        return "Start"
    elif i == 1:
        return "Night Check"
    elif i == 2:
        return "Disconnect"
    elif i == 3:
        return "Night"
    elif i == 4:
        return "Fault"
    elif i == 5:
        return "Bulk"
    elif i == 6:
        return "PWM"
    elif i == 7:
        return "Float"
    elif i == 8:
        return "Equalize"
    else:
        return "Unknown (%d)" % i

def reset_amphours():
    """Resets the AMP hour count on the tristar"""
    global amphours_reset

    if ts_writecoil(0x0010, 0xFF00) != 0xFFFF:
        amphours_reset = time.time()
        return True

    log_warning("Failed to reset AMP hour count")
    return False

@registerRecurring(60)
def monitor_amphours():
    """Called regularly to monitor the amp hours value.

    The main purpose of this function is to reset the amphours to 0 at midnight
    """
    global amphours_reset

    t = time.localtime()
    if t[3] != 0:
        # Not midnight hour
        return

    # Midnight hour, if last amphours reset was before midnight, reset
    now = time.time()
    if amphours_reset > (now-((t[4]+1)*60)):
        return

    log_info("Resetting amp hours to 0")
    reset_amphours()
    return

##############################################################################
# Initialisation
##############################################################################
def ccs_init():

    if not find_tristar():
        return

    # Reset the amp hours
    reset_amphours()

    # Register the SNMP handler
    @registerDynamicOID(CRCNET_TRISTAR45_MIB)
    def wrapper(o, g):
        try:
            return solarsnmp(o,g)
        except:
            log_error("Unexpected error handling solarsnmp!", sys.exc_info())
            return None

    # Add a menu entry
    registerMenuItem(MENU_TOP, MENU_GROUP_GENERAL, \
                    "/status/solar", "Solar Controller Status")

##############################################################################
# Content Pages
##############################################################################
@registerPage("/status/solar")
def solarpage(request, method):
    """Returns information about the solar controller attached to this node"""
    global ts_id, amphours_reset

    if request.query.find("resetAH=true") != -1:
        log_info("Resetting AMP hours at user request")
        reset_amphours()

    ah_reset = time.strftime("%c", time.localtime(amphours_reset))
    info = (ts_id, ts_serial(), ts_hwver(), ts_battv(), ts_battsensev(), \
            ts_arrayv(), ts_chargei(), ts_battvs(), \
            ts_readreg(TS_HSTEMP_DEG), ts_readreg(TS_BATTEMP_DEG), ts_refv(), \
            ah_reset, ts_amphours(), ts_totalamphours(), ts_controlmode_s(), \
            ts_controlstate_s(), ts_pwm(), ts_readreg(TS_KWH))

    # Build interfaces information
    output = """

Solar Controller (%s) Status

    Serial Number:
    %s

    Hardware Version:
    %s

    Battery Voltage:
    %2.2fV

    Battery Sense Voltage:
    %2.2fV

    Array Voltage:
    %2.2fV

    Charge Current:
    %2.2fA

    Battery Voltage (Slow):
    %2.2fV

    Heatsink Temperature:
    %2.0fC

    Battery Temperature:
    %2.0fC

    Reference Voltage:
    %2.2fV

    Amp Hours
(since %s):
    %s
    [reset now]

    Amp Hours (Total):
    %s

    Control Mode:
    %s

    Control State:
    %s

    PWM Duty Cycle:
    %d%%

    Kilowatt Hours:
    %s

""" % info

    returnPage(request, "Solar Controller Status", output)

def solarsnmp(oid, getNext):

    iface = None

    # Strip off the base of the oid
    base = oid[:len(CRCNET_TRISTAR45_MIB)]
    if base != CRCNET_TRISTAR45_MIB:
        log_warn("Invalid base OID passed to solarsnmp: %s" % str(oid))
        return None

    parts = oid[len(CRCNET_TRISTAR45_MIB):]
    if len(parts) < 1:
        # Base OID specified only
        if not getNext:
            # Invalid OID
            log_warn("Invalid OID passed to solarsnmp: %s" % str(oid))
            return None
        else:
            part = 1
        # Assume its the first request in a getNext stream
        oid = CRCNET_TRISTAR45_MIB + (part,)
        item = -1
    else:
        part = parts[0]
        if (part==23 or part==24):
            if len(parts)!=2:
                # Invalid OID
                log_warn("Invalid OID passed to solarsnmp: %s" % str(oid))
                return None
            else:
                item = parts[1]
                if item < 1 or item > 16:
                    # Invalid OID
                    log_warn("Invalid OID passed to solarsnmp: %s" % str(oid))
                    return None
        else:
            item = -1

        if getNext:
            # Advance
            if part==23 or part==24:
                # Handle bitfields specially
                if item==16:
                    # Move to next field
                    part+=1
                    if part==24:
                        item=1
                    else:
                        item=-1
                else:
                    # Move to next bit in this field
                    item+=1
            else:
                if part==25:
                    # End of MIB
                    return None
                part+=1
                if part==23:
                    item=1
                else:
                    item=-1
            oid = CRCNET_TRISTAR45_MIB + (part,)
            if item != -1:
                oid += (item,)

    if part == 1:
        # Battery Voltage
        return (oid, snmp.Integer("%d" % ts_battv()))
    elif part == 2:
        # Battery Sense Voltage
        return (oid, snmp.Integer("%d" % ts_battsensev()))
    elif part == 3:
        # Array/Load Voltage
        return (oid, snmp.Integer("%d" % ts_arrayv()))
    elif part == 4:
        # Battery Charge Current
        return (oid, snmp.Integer("%d" % ts_chargei()))
    elif part == 5:
        # Load Current
        return (oid, snmp.Integer("%d" % ts_loadi()))
    elif part == 6:
        # Battery Voltage (Slow)
        return (oid, snmp.Integer("%d" % ts_battvs()))
    elif part == 7:
        # Heatsink Temperature
        d=ts_readreg(TS_HSTEMP_DEG)
        return (oid, snmp.Integer("%d" % d))
    elif part == 8:
        # Battery Temperature
        d=ts_readreg(TS_BATTEMP_DEG)
        return (oid, snmp.Integer("%d" % d))
    elif part == 9:
        # Charge Regulator Reference Voltage
        return (oid, snmp.Integer("%d" % ts_refv()))
    elif part == 10:
        # Amp Hours Resetable
        return (oid, snmp.Integer("%d" % ts_amphours()))
    elif part == 11:
        # Amp Hours Total
        return (oid, snmp.Integer("%d" % ts_totalamphours()))
    elif part == 12:
        # Hour Meter
        return (oid, snmp.Integer("%d" % ts_hrmeter()))
    elif part == 13:
        # Control Mode
        return (oid, snmp.Integer(ts_readreg(TS_CONTROLMODE)))
    elif part == 14:
        # Control State
        return (oid, snmp.Integer(ts_readreg(TS_CONTROLSTATE)))
    elif part == 15:
        # PWM Duty Cycle
        return (oid, snmp.Integer("%d" % ts_pwm()))
    elif part == 16:
        # Days since last equalize
        return (oid, snmp.Integer(ts_readreg(TS_DSLEQU)))
    elif part == 17:
        # Days since last battery service
        return (oid, snmp.Integer(ts_readreg(TS_DSLBS_D)))
    elif part == 18:
        # Kilowatt Hours
        return (oid, snmp.Integer("%d" % ts_readreg(TS_KWH)))
    elif part == 19:
        # Minimum Battery Voltage
        return (oid, snmp.Integer("%d" % ts_minbv()))
    elif part == 20:
        # Maximum Battery Voltage
        return (oid, snmp.Integer("%d" % ts_maxbv()))
    elif part == 21:
        # Serial Number
        return (oid, snmp.OctetString("%s" % ts_serial()))
    elif part == 22:
        # Hardware Version
        return (oid, snmp.OctetString("%s" % ts_hwver()))
    elif part == 23:
        # Alarm
        i=(ts_readreg(TS_ALARMBITS_B_HI)&0xFFFF)<<16
        i|=(ts_readreg(TS_ALARMBITS_B_LO)&0xFFFF)
        pos = 2**(item-1)
        if (pos&i)==pos:
            # Set
            return (oid, snmp.Integer(1))
        else:
            return (oid, snmp.Integer(0))
    elif part == 24:
        # Fault
        i=ts_readreg(TS_FAULTBITS_B)
        pos = 2**(item-1)
        if (pos&i)==pos:
            # Set
            return (oid, snmp.Integer(1))
        else:
            return (oid, snmp.Integer(0))
    elif part == 25:
        # Dip Switch Settings
        i=ts_readreg(TS_DIPSWITCH_B)
        return (oid, snmp.Integer(i))

    log_warn("Invalid OID passed to solarsnmp: %s" % str(oid))
    return None


import uuid
from django.db import models
from shortuuid.django_fields import ShortUUIDField

from users.models import BaseUserProfile, CompanyProfile

class ServiceLocation(models.Model):
    '''
    Represents a location where an internet service is offered
    '''
    SERVICE_TYPES = [
       ("wifi", 'wifi'),
       ("fibre", "fibre"),
       ("p2p/ptmp", "p2p/ptmp")
    ]

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, null=False, blank=False)
    description = models.TextField()

    operator = models.ForeignKey(CompanyProfile, on_delete=models.CASCADE, null=True, blank=True)

    # Location
    address = models.CharField(max_length=150, null=False, blank=False)
    latitude = models.DecimalField(max_digits=18, decimal_places=15)
    longitude = models.DecimalField(max_digits=18, decimal_places=15)

    # Service
    service = models.CharField(max_length=10, choices=SERVICE_TYPES, null=False, blank=False)
    speed = models.IntegerField()

class SavedLocation(models.Model):
    '''
    Represents the raltionship between a user and the service locations they
    have saved
    '''
    id = ShortUUIDField(primary_key=True, length=6, max_length=6, editable=False)
    saver = models.ForeignKey(BaseUserProfile, on_delete=models.CASCADE, related_name='saved_locations')
    locations = models.ManyToManyField(ServiceLocation)

    def locations_count(self):
        return self.locations.count()

class Regulation(models.Model):
    '''
    Represents the WISP regulation in region in a particular time
    '''
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    region = models.CharField(max_length=60)
    # Body in MDX
    body = models.TextField()
    year = models.DateField(null=True)

    # Timestamp
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


#
# Classification Main
#
# Peter Turney, October 29, 2019
#
# Find a way to score the 2**18 possible outer-totalistic
# automata rules, such that the Game of Life (and hopefully
# other universal cellular automata) gets a high score.
#
# https://www.conwaylife.com/wiki/List_of_Life-like_cellular_automata
#
import golly as g
import numpy as np
import random as rand
import classification_functions as cfuncs
import classification_parameters as cparams
#
# make a list of B/S rules (born/survive -- outer-totalistic)
#
rule_file_name = cparams.rule_file_name
rule_list = cfuncs.txt_BS_rules(rule_file_name)
#
# density range for initial random matrix
#
density_range = cparams.density_range
#
# width and height for initial random square matrix
#
initial_size = cparams.initial_size
#
# number of steps for given run of simulation
#
num_steps = cparams.num_steps
#
# number of random trials to evaluate
#
num_trials = cparams.num_trials
#
# margins for calculating die / shrink / stable /expand / explode
#
# - margins are defined as fractions of the initial population
#
# - e.g.:   margins = [0.2, 0.8, 1.25, 5.0]
#
#           final pop < 0.2 * initial pop   --> die
#           final pop < 0.8 * initial pop   --> shrink
#           final pop < 1.25 * initial pop  --> stable
#           final pop < 5.0 * initial pop   --> expand
#           else                            --> explode
#
margins = cparams.margins
#
# Golly screen magnification
#
screen_mag = cparams.screen_mag
#
# initialize Golly
#
g.setalgo("QuickLife") # select the algorithm for Golly
g.autoupdate(False) # do not update the view unless requested
g.new("Classification") # create a new, empty universe and set the window title
g.setmag(screen_mag) # screen magnification
#
# prepare log file for recording statistics
#
# - use option 0 so that log file writes immediately (no buffer),
#   in case of forced exit (crash)
#
log_path = cparams.log_path
log_handle = open(log_path, "w", 0)
#
# show parameter settings in the log file
#
parameter_settings = cfuncs.show_parameters()
log_handle.write("\nParameter Settings\n\n")
for setting in parameter_settings:
  log_handle.write(setting + "\n")
log_handle.write("\n")
#
# write a header line for the list of results
#
#                "rule  die  shrink  stable expand  explode"
log_handle.write("rule\tdie\tshrink\tstable\texpand\texplode\n")
#
# -------------------------------------------------
# main loop: iterate through the list of rules
# -------------------------------------------------
#
for rule in rule_list:
  #
  # initialize die / shrink / stable /expand / explode
  #
  die_sum = 0.0
  shrink_sum = 0.0
  stable_sum = 0.0
  expand_sum = 0.0
  explode_sum = 0.0
  #
  for trial in range(num_trials):
    #
    # show the rule and the trial number in the Golly header
    #
    g.show(rule + " -- trial " + str(trial + 1))
    #
    # initialize a random matrix
    #
    prob_one = rand.uniform(density_range[0], density_range[1])
    initial_matrix = np.zeros((initial_size, initial_size), dtype=np.int)
    initial_pop_count = 0
    for x in range(initial_size):
      for y in range(initial_size):
        if (rand.uniform(0, 1) <= prob_one):
          initial_matrix[x][y] = 1
          initial_pop_count = initial_pop_count + 1
    #
    # initialize Golly
    #
    g.new("Classification") # make a new, empty Golly universe
    g.setmag(screen_mag) # screen magnification
    g.setrule(rule) # set the rule that Golly will use
    offset = int(initial_size / 2) # this centers the matrix in the display
    # write initial matrix into the Golly universe
    for x in range(initial_size):
      for y in range(initial_size):
        g.setcell(x - offset, y - offset, initial_matrix[x][y])
    #
    # run Golly for num_steps
    #
    g.run(num_steps)
    g.update() # update the Golly display
    #
    # read the updated matrix from the Golly universe
    #
    # - with each step, the matrix size increases by two
    #   new outer columns and two new outer rows
    #
    expanded_size = initial_size + (2 * num_steps)
    updated_matrix = np.zeros((expanded_size, expanded_size), dtype=np.int)
    offset = int(expanded_size / 2) # this centers the matrix in the display
    final_pop_count = 0
    for x in range(expanded_size):
      for y in range(expanded_size):
        if (g.getcell(x - offset, y - offset) == 1):
          updated_matrix[x][y] = 1
          final_pop_count = final_pop_count + 1
    #
    # update die / shrink / stable /expand / explode
    #
    if (final_pop_count < (initial_pop_count * margins[0])):
      die_sum = die_sum + 1
    elif (final_pop_count < (initial_pop_count * margins[1])):
      shrink_sum = shrink_sum + 1
    elif (final_pop_count < (initial_pop_count * margins[2])):
      stable_sum = stable_sum + 1
    elif (final_pop_count < (initial_pop_count * margins[3])):
      expand_sum = expand_sum + 1
    else:
      explode_sum = explode_sum + 1
    #
    # end of trial loop
    #
  #
  # report some statistics
  #
  die_pct = float(die_sum) / num_trials
  shrink_pct = float(shrink_sum) / num_trials
  stable_pct = float(stable_sum) / num_trials
  expand_pct = float(expand_sum) / num_trials
  explode_pct = float(explode_sum) / num_trials
  #
  log_handle.write(rule + "\t" + \
    str(die_pct) + "\t" + \
    str(shrink_pct) + "\t" + \
    str(stable_pct) + "\t" + \
    str(expand_pct) + "\t" + \
    str(explode_pct) + "\n")
  #
  # end of rule loop
  #
#
# close log file
#
log_handle.write("\nDone.\n")
log_handle.close()
#
#


import ast
import sys

if sys.version_info.major==3:unicode=str

class Template(dict):
    def __init__(self, template={}, values={}):
        self._template = template
        super(Template, self).__init__()
        for k in template.keys():
            super(Template, self).__setitem__(k, None)
            # Let setitem check types
            self[k] = values[k] if k in values else None

    def __setitem__(self, key, value):
        if key not in self._template:
            raise KeyError(self.__class__.__name__ +": No such key: "+str(key))

        expected_type = self._template[key]
        bad_value = False
        cast_value = value

        # Cast required
        if value is not None and type(value) is not expected_type:
            # Check for explicit bad casts
            if expected_type is int:
                if type(value) is not int and type(value) is not str:
                    bad_value = True
            elif expected_type is str:
                if type(value) is not str and type(value) is not unicode:
                    bad_value = True
            elif expected_type is list:
                if type(value) is not str:
                    bad_value = True

            # Check for implicit bad casts
            if not bad_value:
                try:
                    if expected_type is list:
                        cast_value = ast.literal_eval(value)
                    else:
                        cast_value = expected_type(value)
                except:
                    bad_value = True # Bad cast

        # Last minute list validation
        if bad_value is False and value is not None and expected_type is list:
            for i in cast_value:
                if type(i) is not str and type(i) is not unicode:
                    bad_value = True
            # Translate unicode strings
            if bad_value is True:
                cast_value = list(map(lambda x: str(x), cast_value))

        if bad_value is True:
            raise TypeError(self.__class__.__name__
                            + ": Bad value for "
                            + key
                            + ": "
                            + str(value))

        super(Template, self).__setitem__(key, cast_value)

    def update(self, values):
        for k,v in values.items():
            if k in self._template:
                # Let setitem check types
                self[k] = values[k]

    def __delitem__(self, k):
        if k not in self:
            raise KeyError(self.__class__.__name__ + ": No such key: " + str(k))
        super(Template, self).__setitem__(k, None)


def invert_str_to_float(data):
    if data == "":
        return None
    else:
        return float(data)

class Verre:

    def __init__(self, data_ligne):
        self.command = data_ligne[0]
        self.oeil = data_ligne[1]
        self.type = data_ligne[2]
        self.matiere = data_ligne[3]
        self.diametre = invert_str_to_float(data_ligne[4])
        self.base = invert_str_to_float(data_ligne[5])
        self.sphere = invert_str_to_float(data_ligne[6])
        self.sphere_mesure = invert_str_to_float(data_ligne[7])
        self.cylindre = invert_str_to_float(data_ligne[8])
        self.cylindre_mesure = invert_str_to_float(data_ligne[9])
        self.axe = invert_str_to_float(data_ligne[10])
        self.axe_mesure = invert_str_to_float(data_ligne[11])
        self.addition = invert_str_to_float(data_ligne[12])
        self.addition_mesure = invert_str_to_float(data_ligne[13])
        self.epais_centre = invert_str_to_float(data_ligne[14])
        self.epais_centre_mesure = invert_str_to_float(data_ligne[15])
        self.sphere_delta = None
        self.cylindre_delta = None
        self.axe_delta = None
        self.addition_delta = None
        self.epais_centre_delta = None
        self.init_all()

    def init_all(self):
        self.calculer_delta()

    def get(self, para):
        if para == "type":
            return self.type
        elif para == "matiere":
            return self.matiere

    def calculer_delta(self):
        if self.sphere and self.sphere_mesure:
            self.sphere_delta = self.sphere - self.sphere_mesure
        else:
            self.sphere_delta = None
        if self.cylindre and self.cylindre_mesure:
            self.cylindre_delta = self.cylindre - self.cylindre_mesure
        else:
            self.cylindre_delta = None
        if self.axe and self.axe_mesure:
            self.axe_delta = self.axe - self.axe_mesure
        else:
            self.axe_delta = None
        if self.addition and self.addition_mesure:
            self.addition_delta = self.addition - self.addition_mesure
        else:
            self.addition_delta = None
        if self.epais_centre and self.epais_centre_mesure:
            self.epais_centre_delta = self.epais_centre - self.epais_centre_mesure
        else:
            self.epais_centre_delta = None


from os.path import join, isdir
from os import listdir, mkdir, makedirs
import sys
import cv2
import numpy as np
import pickle
import json
import glob
from concurrent import futures
import xml.etree.ElementTree as ET

sys.path.append('..')
import utils

debug = False

VID_base_path = "./ILSVRC2015"
save_base_path = join(VID_base_path, 'Curation')
ann_base_path = join(VID_base_path, 'Annotations/VID')
img_base_path = join(VID_base_path, 'Data/VID')

subdir_map = {'train/ILSVRC2015_VID_train_0000': 'a',
              'train/ILSVRC2015_VID_train_0001': 'b',
              'train/ILSVRC2015_VID_train_0002': 'c',
              'train/ILSVRC2015_VID_train_0003': 'd',
              'val': 'e'}

def crop_video(subdir, sub_set, video):
    video_crop_base_path = join(save_base_path, sub_set, video)
    if not isdir(video_crop_base_path): makedirs(video_crop_base_path)

    xmls = sorted(glob.glob(join(ann_base_path, subdir, video, '*.xml')))

    for xml in xmls:

        xmltree = ET.parse(xml)
        objects = xmltree.findall('object')
        objs = []
        filename = xmltree.findall('filename')[0].text

        im = cv2.imread(xml.replace('xml', 'JPEG').replace('Annotations', 'Data'))
        avg_chans = np.mean(im, axis=(0, 1))
        for object_iter in objects:

            trackid = int(object_iter.find('trackid').text)
            bndbox = object_iter.find('bndbox')

            bbox = [int(bndbox.find('xmin').text), int(bndbox.find('ymin').text),
                    int(bndbox.find('xmax').text), int(bndbox.find('ymax').text)]

            z, x = utils.crop_image(im, bbox, padding=avg_chans)
            # cv2.imwrite(join(video_crop_base_path, '{:06d}.{:02d}.z.jpg'.format(int(filename), trackid)), z)
            cv2.imwrite(join(video_crop_base_path, '{:06d}.{:02d}.x.jpg'.format(int(filename), trackid)), x)

def image_curation(num_threads=24):

    for subdir, sub_set  in subdir_map.items():

        sub_set_base_path = join(ann_base_path, subdir)

        videos = sorted(listdir(sub_set_base_path))

        if debug:
          videos = videos[:1]
        n_videos = len(videos)

        with futures.ProcessPoolExecutor(max_workers=num_threads) as executor:
            fs = [executor.submit(crop_video, subdir, sub_set, video) for video in videos]
            for i, f in enumerate(futures.as_completed(fs)):
                # Write progress to error so that it can be seen
                utils.print_progress(i, n_videos, prefix=sub_set, suffix='Done ', barLength=40)

def save_config():
    snippets = dict()

    instance_size = utils.get_instance_size()

    for subdir, sub_set  in subdir_map.items():
        subdir_base_path = join(ann_base_path, subdir)
        videos = sorted(listdir(subdir_base_path))
        for vi, video in enumerate(videos):
            print('subset: {} video id: {:04d} / {:04d}'.format(subdir, vi, len(videos)))

            frames = []
            xmls = sorted(glob.glob(join(subdir_base_path, video, '*.xml')))

            id_set = []
            id_frames = [[]] * 60  # at most 60 objects

            for num, xml in enumerate(xmls):
                f = dict()
                xmltree = ET.parse(xml)
                size = xmltree.findall('size')[0]
                frame_sz = [int(it.text) for it in size]
                objects = xmltree.findall('object')
                objs = []
                for object_iter in objects:
                    trackid = int(object_iter.find('trackid').text)

                    name = (object_iter.find('name')).text
                    bndbox = object_iter.find('bndbox')
                    occluded = int(object_iter.find('occluded').text)
                    o = dict()
                    o['c'] = name
                    o['bbox'] = [int(bndbox.find('xmin').text), int(bndbox.find('ymin').text),
                                 int(bndbox.find('xmax').text), int(bndbox.find('ymax').text)]

                    s_z, scale_z = utils.siamfc_like_scale(o['bbox'])
                    s_x = instance_size / scale_z
                    #print("{}, {}, {}, s_x: {}".format(video, xml, trackid, s_x))
                    bb_center = [(o['bbox'][2]+o['bbox'][0])/2., (o['bbox'][3]+o['bbox'][1])/2.]

                    mask = [0, 0, instance_size-1, instance_size-1]
                    if bb_center[0] < s_x/2:
                      mask[0] = (s_x/2 - bb_center[0]) * scale_z
                    if bb_center[1] < s_x/2:
                      mask[1] = (s_x/2 - bb_center[1]) * scale_z
                    if bb_center[0] + s_x/2 > frame_sz[0]:
                      mask[2] = mask[2] - (bb_center[0] + s_x/2 - frame_sz[0]) * scale_z
                    if bb_center[1] + s_x/2 > frame_sz[1]:
                      mask[3] = mask[3] - (bb_center[1] + s_x/2 - frame_sz[1]) * scale_z

                    o['mask'] = mask

                    o['trackid'] = trackid
                    o['occ'] = occluded
                    objs.append(o)

                    if trackid not in id_set:
                        id_set.append(trackid)
                        id_frames[trackid] = []
                    id_frames[trackid].append(num)

                f['frame_sz'] = frame_sz
                f['img_path'] = xml.split('/')[-1].replace('xml', 'JPEG')
                f['objs'] = objs
                frames.append(f)

            if len(id_set) > 0:
                snippets[join(sub_set, video)] = dict()
                snippets[join(sub_set, video)]['frame_size'] = frames[0]['frame_sz']
                snippets[join(sub_set, video)]['tracks'] = dict()

            for selected in id_set:
                frame_ids = sorted(id_frames[selected])
                sequences = np.split(frame_ids, np.array(np.where(np.diff(frame_ids) > 1)[0]) + 1)
                sequences = [s for s in sequences if len(s) > 1]  # remove isolated frame.
                for seq in sequences:
                    snippet = dict()
                    for frame_id in seq:
                        frame = frames[frame_id]
                        for obj in frame['objs']:
                            if obj['trackid'] == selected:
                                o = obj
                                continue
                        snippet[frame['img_path'].split('.')[0]] = o['bbox']
                    snippets[join(sub_set, video)]['tracks']['{:02d}'.format(selected)] = snippet

            if debug:
              break

    train = {k:v for (k,v) in snippets.items() if 'train' in k}
    val = {k:v for (k,v) in snippets.items() if 'val' in k}

    json.dump(train, open(join(save_base_path,'train.json'), 'w'), indent=4, sort_keys=True)
    json.dump(val, open(join(save_base_path,'val.json'), 'w'), indent=4, sort_keys=True)

    with open(join(save_base_path, 'train.pickle'), 'wb') as f:
        pickle.dump(train, f)

    with open(join(save_base_path, 'val.pickle'), 'wb') as f:
        pickle.dump(val, f)

if __name__ == '__main__':

    if not isdir(save_base_path): mkdir(save_base_path)

    print("crop the images for training")

    if len(sys.argv) == 2:
        image_curation(sys.argv[1])
    else:
        image_curation()

    print("save the configuration for the curation data")

    save_config()


import math
import random

import pygame

import globals as g

from vector2 import Vector2

class Fox:
    def __init__(self, x, y):
        self.location = Vector2(x, y)
        self.hunger = 100
        self.radius = 20
        self.direction = Vector2(0, 1)

        self.currently_eating_timer = 0
        self.move_timer = 0
        self.hunger_timer = 0

        self.currently_eating = False
        self.hunting = False
        self.rab = None
        self.checked_camo = False
        self.escaped_rabbits = []

    def draw(self, screen):
        pygame.draw.circle(screen, g.fox_orange, self.location.return_tuple(), self.radius)

    def hunt_rabbit(self):
        dist = self.location.find_distance(self.rab.location)
        if dist > 40:
            self.hunting = False
            self.rab = None
            self.checked_camo = False
            return False
        elif self.rab.hiding:
            self.hunting = False
            self.rab = None
            self.checked_camo = False
            return False
        elif self.rab.camouflaging and not self.checked_camo:
            r = random.random()
            r *= 100
            if self.rab.camouflaging:
                if self.rab.dna.color == g.light:
                    if r > 80:
                        print("escaped")
                        self.escaped_rabbits.append(self.rab)
                        self.hunting = False
                        self.rab = None
                        self.checked_camo = False
                        return False
                elif self.rab.dna.color == g.mid:
                    if r > 60:
                        print("escaped")
                        self.escaped_rabbits.append(self.rab)
                        self.hunting = False
                        self.rab = None
                        self.checked_camo = False
                        return False
                else:
                    if r > 40:
                        print("escaped")
                        self.escaped_rabbits.append(self.rab)
                        self.hunting = False
                        self.rab = None
                        self.checked_camo = False
                        return False
                self.checked_camo = True
        elif dist < self.rab.radius:
            g.fox_deaths += 1
            self.rab.be_eaten()
            self.eat()
            self.checked_camo = False
            return True
        else:
            self.direction.set_new_direction(self.rab.location, self.location)
            return True

    def check_for_rabbits(self):
        for r in g.rabbits:
            if not r.hiding and r not in self.escaped_rabbits:
                dist = self.location.find_distance(r.location)
                if dist < r.radius:
                    self.rab = r
                    self.rab.be_eaten()
                    self.eat()
                    return False

                if dist < 40:
                    vec = Vector2(r.location.x - self.location.x, r.location.y - self.location.y)
                    vec.find_unit_vector()
                    cos_ang = vec.find_dot_product(self.direction)
                    if -1 <= cos_ang <= 1:
                        ang = math.acos(cos_ang)
                        ang = math.degrees(ang)
                        if ang < 45:
                            self.rab = r
                            self.hunting = True
                            return True
        return False

    def set_direction(self):
        if self.currently_eating:
            self.eat()
            return

        if not self.hunting:
            if self.check_for_rabbits():
                if not self.currently_eating:
                    if self.hunt_rabbit():
                        return
        elif self.hunt_rabbit():
            return

        if not self.currently_eating:
            # The random number will determine whether the fox keeps moving in the same direction or changes course
            rand = random.randint(0, 500)
            if rand < 20:
                rand_x = random.randint(0, g.screen_width)
                rand_y = random.randint(0, g.screen_height)
                self.direction.x = rand_x
                self.direction.y = rand_y
                self.direction.set_new_direction(Vector2(rand_x, rand_y), self.location)

    def update_escaped_rabbits(self):
        for rab in self.escaped_rabbits:
            if not rab.camouflaging:
                self.escaped_rabbits.remove(rab)

    def die(self):
        g.foxes.remove(self)

    def eat(self):
        self.currently_eating = True
        self.hunger = 100
        self.hunger_timer = 0
        self.direction.x = 0
        self.direction.y = 0
        self.currently_eating_timer += 1
        if self.currently_eating_timer > 15:
            # Finish eating
            self.currently_eating_timer = 0
            self.currently_eating = False
            self.hunting = False
            self.rab.die()
            self.rab = None

    def move(self):
        if self.move_timer > 70:

            # Implement hunger
            if self.hunger_timer > 20:
                self.hunger -= 1
                self.hunger_timer = 0

            if self.hunger < 0:
                self.die()

            # Update the escaped rabbits
            self.update_escaped_rabbits()

            # Set new direction of travel
            self.set_direction()

            # Make direction a unit vector
            self.direction.find_unit_vector()

            # Increment location based on new direction
            self.location.add(self.direction)

            # Increment event timers
            self.hunger_timer += 1
            self.move_timer = 0
        else:
            self.move_timer += 1


from tkinter import *

root = Tk()

# Making the entry field
e = Entry(root)
e.insert(0, "Enter Your Name")
#Putting it on the screen
e.grid(row = 0, column = 0)

def button_function():
    name = e.get()
    msg = Label(root, text =f"Hello, {name}")
    msg.grid(row = 2, column = 0)

# Making the button
button = Button(root, text="Click", command = button_function)
button.grid(row = 1, column = 0)

root.mainloop()


from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By

import pandas as pd

# load data url
df = pd.read_csv('D:/Sadasa Academy/training-scraping/learn-selenium/scrape-bhinneka-sarung-url.csv')
df = df.dropna()
urls = df['url'].values.tolist()

options = Options()
# options.add_experimental_option("detach", True)

# options for making the browser headless
options.add_argument("--headless")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--no-sandbox")

driver = Chrome(executable_path='/d/Sadasa Academy/training-scraping/learn-selenium/chromedriver.exe',
                options=options)

def close_popup(driver):
    popup_button = driver.find_element(by=By.XPATH, value='//*[@id="onesignal-slidedown-cancel-button"]')
    popup_button.click()

product_details = []

for i in range(len(urls)):
    try:
        driver.get(urls[i])
        driver.implicitly_wait(7)

    except NoSuchElementException:
        close_popup()
        driver.get(urls[i])
        driver.implicitly_wait(7)

    try:
        # get product title
        title_xpath = '//*[@id="__next"]/div[4]/div[2]/div[2]/div[2]/div/h1'
        product_title = driver.find_element(by=By.XPATH, value=title_xpath).text

    except NoSuchElementException:
        product_title = 'Unsuccessful'

    try:
        # get product price
        price_xpath = '//*[@id="__next"]/div[4]/div[2]/div[2]/div[2]/div/div[3]/div/div/h4'
        product_price = driver.find_element(by=By.XPATH, value=price_xpath).text

    except NoSuchElementException:
        product_price = 'Unsuccessful'

    try:
        # get product code
        product_code_xpath = '//*[@id="__next"]/div[4]/div[2]/div[2]/div[2]/div/div[2]/div[1]/span'
        product_code = driver.find_element(by=By.XPATH, value=product_code_xpath).text

    except NoSuchElementException:
        product_code = 'Unsuccessful'

    try:
        # get shop's name
        try:
            shop_xpath = '//*[@id="__next"]/div[4]/div[2]/div[2]/div[2]/div/div[7]/div/a'
            shop_name = driver.find_element(by=By.XPATH, value=shop_xpath).text

        except NoSuchElementException:
            shop_xpath = '//*[@id="__next"]/div[4]/div[2]/div[2]/div[2]/div/div[8]/div/a'
            shop_name = driver.find_element(by=By.XPATH, value=shop_xpath).text

    except NoSuchElementException:
        shop_name = 'Unsuccessful'

    detail = {
        'product_title' : product_title,
        'product_price' : product_price,
        'product_code'  : product_code,
        'shop_name'     : shop_name
    }

    product_details.append(detail)
    print(f'scraped ke-{i+1}')

# convert list to dataframe
df = pd.DataFrame(product_details)

# save to csv file
df.to_csv('hasil-scrape-bhinneka-detail-produk-sarung-url.csv', index=False)

# close driver
print('scraping selesai.')
driver.close()


# Import necessary libraries
import pandas as pd
import json
import openpyxl
from openpyxl.styles import Alignment, PatternFill, Font
from openpyxl.utils import get_column_letter

# Open and read the content of the Installments.json file
with open('Installments.json', 'r', encoding='utf-8') as file:
    data = json.load(file)

# Convert the JSON data to a pandas DataFrame for easier processing
df_main = pd.json_normalize(data)

# Dictionary for renaming specific columns to more human-readable names
column_renaming = {...}  # [truncated for brevity]

# Rename the columns in the DataFrame based on the dictionary
df_main.rename(columns=column_renaming, inplace=True)

# List of columns to be removed from the DataFrame
columns_to_drop = [...]  # [truncated for brevity]

# Drop the specified columns if they exist in the DataFrame
df_main = df_main.drop(columns=[col for col in columns_to_drop if col in df_main.columns])

# Dictionary to map messenger types to their proper names
messenger_mapping = {...}  # [truncated for brevity]

# Replace values in the 'Internal Messenger Type' column based on the mapping dictionary
df_main['Internal Messenger Type'] = df_main['Internal Messenger Type'].replace(messenger_mapping)

# Capitalize the values in the "Status" column for consistency
df_main['Status'] = df_main['Status'].str.capitalize()

# Capitalize the values in the "Gender" column for consistency
df_main['Gender'] = df_main['Gender'].str.capitalize()

# Save the processed DataFrame to an Excel file
output_file = 'output.xlsx'
with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
    df_main.to_excel(writer, sheet_name='Main', index=False)

# Load the saved Excel file back into memory for formatting
wb = openpyxl.load_workbook(output_file)

# Define styles for formatting cells in the Excel sheet
font = Font(name='Vazirmatn')
alignment = Alignment(horizontal='center', vertical='center')
light_yellow_fill = PatternFill(start_color="FFFF99", end_color="FFFF99", fill_type="solid")
light_green_fill = PatternFill(start_color="CCFFCC", end_color="CCFFCC", fill_type="solid")

# Apply the defined styles to cells in the Excel sheet
sheet = wb['Main']
for row in sheet:
    for cell in row:
        cell.font = font
        cell.alignment = alignment
        cell.number_format = '@'  # Set number format to text
        # Differentiate the header row with a unique background color
        if cell.row == 1:
            cell.fill = light_yellow_fill
        else:
            cell.fill = light_green_fill

    # Adjust the width of each column based on the max length of its content
    for column_cells in sheet.columns:
        length = max(len(str(cell.value)) for cell in column_cells)
        sheet.column_dimensions[get_column_letter(column_cells[0].column)].width = length

# Save the formatted Excel file
wb.save(output_file)


#!/usr/bin/env python
# coding: utf-8
from __future__ import print_function
import argparse
from datetime import datetime
import os, sys
import cv2
import numpy as np
from models import *
import math
import glob
import torch
import torch.nn as nn
import torch.optim
from torch.optim.lr_scheduler import MultiStepLR
import scipy.io as sio

from skimage.measure.simple_metrics import compare_psnr
from skimage.measure import compare_ssim
from utils.common_utils import *
from torch.distributions import Poisson
import matplotlib.pyplot as plt

parser = argparse.ArgumentParser(description="PR_Poisson_noise")
parser.add_argument("--imgs-dir", type=str, default='Unatural256', help="directory of testing images")
parser.add_argument("--masktype", type=str, default='bipolar', help="type of mask")
parser.add_argument("--noisetype", type=str, default='poisson', help="type of noise")
parser.add_argument("--nummask", type=int, default=3, help="number of masks")
parser.add_argument("--gpuid", type=int, default=0, help="gpu id")
parser.add_argument("--numits", type=int, default=10000,help="Number of training iterations")

opts = parser.parse_args()
os.environ["CUDA_VISIBLE_DEVICES"] = str(opts.gpuid)
torch.set_num_threads(8)

torch.backends.cudnn.enabled = True
torch.backends.cudnn.benchmark =True
dtype = torch.cuda.FloatTensor

# define the add noise module
def add_noise(model, nlevel):
    for n in [x for x in model.parameters() if len(x.size()) == 4]:
        noise = torch.randn(n.size())*nlevel
        noise = noise.type(dtype)
        n.data = n.data + noise

class Logger(object):
    def __init__(self, fileN="Default.log"):
        self.terminal = sys.__stdout__
        self.log = open(fileN, "a+")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)
        self.flush()
#        self.close()
    def flush(self):
        self.log.flush()

input_depth = 32
lr = 0.01 # learning rate

INPUT =     'noise'

reg_noise_std = 0.01 # the input noise helps the performance
psnr_trace=[]
psnr_noavg_trace = []
loss_trace=[]
trace ={}

burnin_iter = 2000
weight_decay = 5e-8 # help for the performance

sgld_mean_each = 0
sgld_mean_tmp = 0

class Ax_pr_cdp(nn.Module):
    def __init__(self, c,h,w,masktype):
        super(Ax_pr_cdp, self).__init__()
        self.c=c
        self.h=h
        self.w=w
        if masktype == 'uniform':
            ang = 2*torch.acos(torch.zeros(1)).item()*2*torch.rand(c,h,w,1)
            self.mask = torch.cat((torch.cos(ang),torch.sin(ang)), 3).cuda()
        elif masktype == 'bipolar':
            self.mask = 2.0*(torch.bernoulli(0.5*torch.ones(c,h,w,2))-0.5).cuda()

    def forward(self, img):
        img_s=img.reshape(1,self.h,self.w,1).repeat(self.c,1,1,2)*self.mask
        meas=torch.fft(img_s,2,normalized=True)
        meas= torch.sqrt(meas[:,:,:,0]**2+meas[:,:,:,1]**2)
        return meas

if opts.noisetype == 'poisson':
    alpha = 9 # Noise level, choices from [9,27, 81]
    if opts.imgs_dir == 'Natural256':
        nlevel = 1e-10 # tuneable for different noise level, which depends on the noise level and the accuracy of the estimated noise
    else:
        nlevel = 1e-12 # the smaller the alpha value, the smaller the nlevel is
elif opts.noisetype == 'awgn':
    alpha = 10 #[10, 15, 20]
    if opts.imgs_dir == 'Natural256':
        nlevel = 1e-5 # tuneable for different noise level, which depends on the noise level and the accuracy of the estimated noise
    else:
        nlevel = 1e-7 # Generally for unnatural256 images, we set nlevel smaller for better performance
else:
    alpha = 0
    nlevel = 0.0001

file_name = glob.glob('./PRImageSet/'+opts.imgs_dir+'/*.png' )
data_num = len(file_name)
psnr_a = np.zeros((data_num,))
ssim_a = np.zeros((data_num,))

psnr_aver = 0.0
ssim_aver = 0.0
num_iter = opts.numits
for fi,Img_Name in enumerate(file_name): #[0:1]
    MODEL_PATH = './Github_PR_est_noise_poi_FINAL/PR_Recon_Results/%s_alpha%2d/%s/' % (opts.noisetype, opts.masktype, opts.imgs_dir,alpha,Img_Name[Img_Name.rfind('/')+1:-4])
    if not os.path.exists(MODEL_PATH):
        os.makedirs(MODEL_PATH)
    sgld_mean_each = 0
    sgld_mean_tmp = 0
    img = np.array(cv2.imread(Img_Name, -1), dtype=np.float32)/255.
    if img.ndim == 2:
        Img = np.expand_dims(img, axis=0)
    else:
        Img = img.transpose(2,0,1)
    c,w,h = Img.shape
    Ax=Ax_pr_cdp(opts.nummask,w,h,opts.masktype)
    Img = np.expand_dims(Img,axis=1)
    Img_tensor = torch.FloatTensor(Img).cuda()

    meas_nf = Ax(Img_tensor)
    if opts.noisetype == 'poisson':
        meas_nf_before = meas_nf
        intensity_noise=alpha/255.0*(meas_nf)*torch.randn(meas_nf.shape).cuda()

        y2=meas_nf**2+intensity_noise
        y2=torch.clamp(y2,min=0.0)

        Measure= torch.sqrt(y2)
        error = torch.mean((Measure - meas_nf_before)**2) # oracle noise, which is not accessiable
        error_est = (alpha/255.0)**2/4 #/(Measure.shape[0]*Measure.shape[1]*Measure.shape[2])
        sys.stdout = Logger(MODEL_PATH+'results.txt')
        print('error {:f} error_est {:f}'.format(error, error_est))
    elif opts.noisetype == 'awgn':
        noise_std=torch.randn(meas_nf.shape).cuda()
        noise = noise_std*torch.norm(meas_nf)/torch.norm(noise_std)/float(np.sqrt(10.0**(alpha/10.0)))

        y2=meas_nf+noise
        Measure=torch.clamp(y2,min=0.0)
        error = torch.mean((Measure - meas_nf)**2)
        error_est = torch.mean(Measure**2)/(float(np.sqrt(10.0**(alpha/10.0))))**2
        sys.stdout = Logger(MODEL_PATH+'results.txt')
        print('error {:f} error_est {:f}'.format(error, error_est))
    else :
        sys.stdout = Logger(MODEL_PATH+'results.txt')
        print('no noise')
        Measure = meas_nf
        error = 0

    img_name = Img_Name
    net_input = get_noise(input_depth, INPUT, (w,h)).type(dtype).detach()

    NET_TYPE = 'skip' #'skip' # UNet, ResNet
    net = get_net(input_depth, NET_TYPE, 'reflection',
                    skip_n33d=128,
                    skip_n33u=128,
                    skip_n11=4,
                    num_scales=5,
                    upsample_mode='bilinear',
                    n_channels=c).type(dtype)

    # Losses
    mse = torch.nn.MSELoss().type(dtype)

# # Define closure and optimize

    def closure():
        global i, num_iter, net_input, psnr_trace, psnr_noavg_trace, loss_trace, trace, sgld_mean_tmp, sgld_mean_each

        if reg_noise_std > 0:
            net_input = net_input_saved + (noise.normal_() * reg_noise_std)
        else:
            net_input = net_input_saved

        Img_rec = net(net_input)

        net_output = Ax(Img_rec)

        total_loss = mse(net_output, Measure)

        total_loss.backward()

        if i > burnin_iter:
            sgld_mean_each += Img_rec
            sgld_mean_tmp = sgld_mean_each / (i-burnin_iter)
        else:
            sgld_mean_tmp = Img_rec

        if (i + 1) % 10 == 0:
            psnr_noavg = compare_psnr(np.squeeze(torch_to_np(Img_rec)),img,1.)
            ssim_noavg = compare_ssim(np.squeeze(torch_to_np(Img_rec)),img,data_range = 1.)
            psnr = compare_psnr(np.squeeze(torch_to_np(sgld_mean_tmp)),img,1.)
            ssim = compare_ssim(np.squeeze(torch_to_np(sgld_mean_tmp)),img,data_range = 1.)
            now = datetime.now()
            sys.stdout = Logger(MODEL_PATH+'results.txt')
            print(img_name, "loss in ", i + 1, ":", total_loss.item(),"psnr_noavg:",psnr_noavg, "psnr:",psnr, now.strftime("%H:%M:%S"))

            loss_trace = np.append(loss_trace,total_loss.item())
            psnr_trace= np.append(psnr_trace,psnr)
            psnr_noavg_trace = np.append(psnr_noavg_trace,psnr_noavg)

            trace['loss'] = loss_trace

            trace['psnr'] = psnr_trace
            trace['psnr_noavg'] = psnr_noavg_trace

            sio.savemat(MODEL_PATH+'trace.mat',trace)

            if i == num_iter - 1:
                # save the image
                plt.plot(psnr_trace)
                plt.plot(psnr_noavg_trace)
                plt.savefig(os.path.join(MODEL_PATH,'comp.png'))
        if (i + 1) % 500 == 0 :
            cv2.imwrite(MODEL_PATH+img_name[img_name.rfind('/')+1:-4] + '_bipolar_poisson_%2d_itn%d_%0.4f_%0.2f.png'%(alpha,i+1,psnr,ssim), np.int32(255*np.squeeze(torch_to_np(sgld_mean_tmp))))

        i += 1

        return total_loss

    net_input_saved = net_input.detach().clone()
    noise = net_input.detach().clone()
    i = 0

    sys.stdout = Logger(MODEL_PATH+'results.txt')
    print('Starting optimization with ASGLD')
    optimizer = torch.optim.Adam(net.parameters(), lr=lr, weight_decay=weight_decay)
    scheduler = MultiStepLR(optimizer, milestones=[5000, 6000, 7000], gamma=0.5)  # learning rates
    stop_iter = -1
    for j in range(num_iter):
        scheduler.step(j)
        optimizer.zero_grad()
        loss = closure()
        optimizer.step()
        nlevel_ = nlevel*math.exp(30*((error_est/loss)-1))
        add_noise(net, nlevel_)

    Img_rec = np.squeeze(torch_to_np(sgld_mean_tmp))

    torch.save({
        'net': net,
        'net_input': net_input,
        'iters': i + 1,
        'net_state_dict': net.state_dict(),
    }, MODEL_PATH +img_name[img_name.rfind('/')+1:-4]+ 'checkpoint_best.pth')

    psnr_single = compare_psnr(img.reshape(h,w),Img_rec.reshape(h,w),1.)
    ssim_single = compare_ssim(img.reshape(h,w),Img_rec.reshape(h,w),data_range = 1.) #compare_ssim(Img.reshape(h,w),Img_rec/255.0,data_range = 1.)
    psnr_aver+=psnr_single
    ssim_aver+=ssim_single
    psnr_a[fi]=psnr_single
    ssim_a[fi]=ssim_single
    sys.stdout = Logger(MODEL_PATH+'psnr.txt')
    print("alpha:", alpha, img_name, "psnr:",psnr_single,ssim_single)

psnr_aver /= len(file_name)
ssim_aver /= len(file_name)
sys.stdout = Logger(MODEL_PATH+'psnr.txt')
print("alpha:", alpha, "average psnr over the image set:", psnr_aver,"average ssim over the image set:", ssim_aver,'\n')
sio.savemat('./Github_PR_est_noise_poi_FINAL/PR_Recon_Results/%s_PSNR_SSIM_%s_%s_DIP.mat'%(opts.imgs_dir,opts.masktype,opts.noisetype), {'psnr_a':psnr_a,'ssim_a':ssim_a})


# coding: utf-8
# In[ ]:
# Reference: https://gist.github.com/carmelom/4dd407d307b2fb1dc99b017835ce8432

import numpy as np
from PIL import Image

from scipy.optimize import curve_fit

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name", type=str, help="image name")
parser.add_argument("-l", "--pix-len", type=float, help="camera pixel size [m]", default="4.84e-6") #1800U 500m pixel size is 2.2 * 2.2
parser.add_argument("-p", "--pow", type=float, help="Total beam power [W]",)

parser.add_argument("--no-plot", action="store_true",
                    help="suppress plotting the output")

args = parser.parse_args()

# supported_formats = ['.tif', '.tiff', '.pgm', '.ppm']

name = args.name

im = Image.open(name)
im = np.asarray(im).astype(float)
if len(im.shape) > 2:
    im = im.mean(axis=-1)

def gaussianbeam(x, a, m, w, offs):
    return a*np.exp(-2*(x-m)**2/w**2) + offs

pix_len = args.pix_len
Pow = args.pow if args.pow is not None else np.nan

Isat = 6.26 # mW/cm^2, Na D2 transition

h, w = im.shape
x = np.arange(w)
y = np.arange(h)

# fit x
xdata = x
ydata = im.sum(0)
# a, m, w, offs
p0 = (ydata.max(), xdata.max()/2, xdata.max()/4, im[0,0])
px, cov = curve_fit(gaussianbeam, xdata, ydata, p0)
mx, wx = px[1], abs(px[2])

# fit y
xdata = y
ydata = im.sum(1)
# a, m, w, offs
p0 = (ydata.max(), xdata.max()/2, xdata.max()/4, im[0,0])
py, cov = curve_fit(gaussianbeam, xdata, ydata, p0)
my, wy = py[1], abs(py[2])

# calculate other quantities
if args.pow is None:
    print("No input power specified")

I0 = 0.2*Pow/(np.pi*wx*wy*pix_len**2)
isat = I0/Isat
omega = 0.5 * np.sqrt(isat)

text = """
Gaussian beam intensity fit

pixel size: {px:g} um

waist x: {wx:g} um
waist y: {wy:g} um

I0: {i0:.2f} mW/cm^2
+ I/I_sat: {isat:.2f}
+ Rabi fr: {omega:.2f} Gamma
""".format(px=pix_len*1e6, wx=wx*pix_len*1e6, wy=wy*pix_len*1e6, i0=I0, isat=isat, omega=omega)
print(text)

# plot
print("Plotting: ", not args.no_plot)
if not args.no_plot:
    import matplotlib.pyplot as plt
    from matplotlib.patches import Ellipse
    fig, [[ax_y, ax_im], [ax_text, ax_x]] = plt.subplots(2,2,  figsize=(12,12),
                                             gridspec_kw={'height_ratios':[2,1], 'width_ratios':[1,2]},)

    ax_im.imshow(im, origin='lower')
    ax_im.axis('off')

    ax_im.get_shared_x_axes().join(ax_im, ax_x)
    ax_im.get_shared_y_axes().join(ax_im, ax_y)

    ax_x.plot(x, im.sum(0))
    ax_x.plot(x, gaussianbeam(x, *px), 'r')
    ax_x.grid()

    ax_y.plot(im.sum(1), y)
    ax_y.plot(gaussianbeam(y, *py), y, 'r')
    ax_y.grid()

    e = Ellipse((mx, my), 2*wx, 2*wy, color='none', ec='w', linestyle='--')
    ax_im.add_patch(e)

    ax_text.text(-0.05, 0.6, text, ha='left', va='center', fontdict={'family': 'monospace', 'size': 14})
    ax_text.axis('off')
    plt.show()


import numpy as np
import matplotlib.pyplot as plt

#Variables
Ca = 0.515 #m
h = 0.248/2 #cm

#Step for each point
step=0.00001

#First Section
z0=np.arange(h,Ca+step,step)
y0=Ca*h/(Ca-h)-z0*h/(Ca-h)

#Second Section
z1=z0
y1=-y0

#Third Section
y2=np.arange(0,h+step,step)
z2=np.ones(len(y2))*h

#Fourth Section
y3=-y2
z3=z2

#FIfth Section
z4=np.arange(0,h+step,step)
y4=np.sqrt(-(z4-h)**2+h**2)

#Sixth Section
z5=z4
y5=-y4

#Plot all the sections
plt.plot(z0,y0,'bo')
plt.plot(z1,y1,'ro')
plt.plot(z2,y2,'go')
plt.plot(z3,y3,'ko')
plt.plot(z4,y4,'ko')
plt.plot(z5,y5,'go')
plt.grid()
plt.show()


# -*- coding: utf-8 -*-
"""
Created on Wed Dec 5 09:29:34 2018

@author: cokelaef
"""
import logging

from django.conf import settings
from pymongo import MongoClient, errors

"""
    MongoConnector Class
    ----------
    Handle basic connection for mongoDB
"""
logger = logging.getLogger('basiclogger')

class Mongosettings:
    def __init__(self):
        self.MONGO_DBNAME = settings.MONGO_DBNAME
        self.MONGO = settings.MONGO

mongo_settings = Mongosettings()

class MongoConnector():
    def __init__(self, dbname=None, mongo = None):
        self.mongo = mongo
        self.client = None
        self.db = None

        if dbname:
            self.dbname = dbname
        else:
            self.dbname = None

    def __enter__(self):
        try:
            self.client = MongoClient(self.mongo, serverSelectionTimeoutMS=200)
            if self.dbname:
                self.db = self.client[self.dbname]
            else:
                self.db = self.client[__name__.split('.')[0]]
            return self
        except errors as e:
            raise e

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.client.close()

def insertdocument(document, collection=None):
    with MongoConnector(mongo_settings.MONGO_DBNAME, mongo_settings.MONGO) as connector:
        if collection == None:
            collection = 'transaction'
        try:
            collection = connector.db[collection]
            return collection.insert_one(document).inserted_id
        except Exception as e:
            if settings.DEBUG == True:
                logger.warning(".mongoconnector.py : connector info {0}, {1}".format(connector.client, connector.db))
                logger.warning(".mongoconnector.py : {0}".format(e))
            else:
                logger.error(".mongoconnector.py : connector info {0}, {1}".format(connector.client, connector.db))
                logger.error(".mongoconnector.py : {0}".format(e))
                raise e


# https://leetcode.com/discuss/interview-question/1482150/rotatedrectsum-codesignal-quora-two-sigma-oa
# Calc max rotated 45d rectangle of (a,b), (b,a) within matrix

def perimetr(matr, i, j, w, h):
  s = matr[i][j]
  dd = [(h, 1, 1)] if w == 1 else [(w, 1, -1)] if h == 1 else [(w, 1, -1), (h, 1, 1), (w, -1, 1), (h-1, -1, -1)]
  for n, x, y in dd:
    if n <= 1: break
    c = 1
    while c < n:
      i += x
      j += y
      c += 1
      s += matr[i][j]
  return s

def rectangles(matr, w, h):
  mm = 0
  for w_, h_ in [(w, h), (h, w)]:
    for j in range(w_-1, len(matr[0])-(h_-1)): # rectangle cols spread [j-(w-1), j+(h-1)]
      for i in range(len(matr)-(w_+h_-1)+1): # each rectangle spreads w+h-1 rows
        # square at (i,j) is sum of all perimeters of inner rectangles
        mm = max(mm, sum([perimetr(matr, i+k, j+max(k-1,0), w_-k, h_-k) for k in range(min(w_, h_))]))
  return mm

matrix = [[1,2,3,4,0],[5,6,7,8,1],[3,2,4,1,4],[4,3,5,1,6]]

print(rectangles(matrix, 2, 3))

# print(perimetr(matrix, 1, 2, 2, 1))


class GD(object):

    def __init__(self, map, symbols):
        self._symbols = symbols

        # Size of one map unit in y, x length
        empty_block = self.get(' ')
        self.size = (len(empty_block), len(empty_block[0]))

        self.map = self.trans_map(map)
        self.act_map = [list(i) for i in map]

    def get(self, symbol, symbol_num=0):
        """Returns a copy of the transformed symbol"""
        return self._symbols[symbol][symbol_num][:]

    def print_map(self, y_range, x_range):
        new_map = [i[x_range[0]:x_range[1]]
                    for i in self.map[y_range[0]: y_range[1]]]
        for i in new_map:
            print(''.join(i))

    def update(self, symbol_map):
        """Updates the Display Map using the Symbol Map"""
        self.map = self.trans_map(symbol_map)

    def trans_map(self, map):
        """Takes each line and transforms it, returning a new map"""
        new_map = self.trans_line(map[0])

        for i in range(1, len(map)):
            new_lines = self.trans_line(map[i])
            new_map += new_lines

        return [list(i) for i in new_map]

    def trans_line(self, line):
        """Takes a line and transforms each symbol, the line may turn
        into multiple lines
        """
        #Start the new lines, one symbol turns into multiple lines
        new_lines = self.get(line[0])

        #For each symbol, retrieve its map and add each line to the
        #corresponding line in new_lines
        for i in range(1, len(line)):
            new_symbol = self.get(line[i])

            for j in range(len(new_symbol)):
                new_lines[j] += new_symbol[j]

        return new_lines

    def trans_coords(self, coords, map):
        """Takes coords from *map* and returns the top left corner
        coords of the corresponding field from the other map as a list
        """
        y, x = coords
        y_len, x_len = self.size

        if map == "disp_map":
            # Get the nearest number, gets next number if more than half
            y_new = (y + y_len // 2) // y_len
            x_new = (x + x_len // 2) // x_len
            # Extra case at end of map, nearest field is 0 again
            if x_new >= len(self.act_map[y_new]):
                x_new = 0

            return [y_new, x_new]

        elif map == "act_map":
            return [y * y_len, x * x_len]

    def display(self, symbol, coords, symbol_num=0):
        """Paints *symbol* on map in position *coords*"""
        pic = self.get(symbol, symbol_num)
        # Define starting point: line(y) and pos(x) in line
        y, x = coords

        for i in range(len(pic)):
            for j in range(len(pic[0])):
                x_index = x + j
                # If pixel goes over edge on x axis: wrap it around
                if x + j >= len(self.map[y + i]):
                    x_index = (x + j) % len(self.map[y + i])

                self.map[y + i][x_index] = pic[i][j]

    def check_collision(self, obj1, obj2):
        """Checks for a collision between two objects using their coords"""
        # Coords are always only the upper left-hand corner of object
        # so first get all four corners of objects by adding size
        y1 = [obj1[0], obj1[0] + self.size[0]-1]
        x1 = [obj1[1], obj1[1] + self.size[1]-1]

        y2 = [obj2[0], obj2[0] + self.size[0]-1]
        x2 = [obj2[1], obj2[1] + self.size[1]-1]

        # Now check if y ranges overlap, then check x ranges
        if y1[0] <= y2[1] and y1[1] >= y2[0]:
            return x1[0] <= x2[1] and x1[1] >= x2[0]
        else:
            return False


from  pynput.keyboard import Key, Listener
from pyo import *
import numpy as np

class myfreq(object):
    def __init__(self):
        self.bf = 440
        self.sp = np.linspace(0,11,12)
        self.tune = self.bf*2**(1/12*self.sp)

    def incres(self):
        self.tune *= 2

    def decres(self):
        self.tune /= 2

def on_press(key):
    global am,flag
    keyStr = eval(key.__str__())
    if keyStr in fqdict:
        am.freq = float(fq.tune[fqdict[keyStr]])
        env.play()
    elif keyStr == 'g':
        fq.decres()
    elif keyStr == 'h':
        fq.incres()
    elif key == Key.tab:
        if flag:
            am = Sine(ap.rnd, mul=globalamp*env).out()
        else:
            am = Sine(ap.rnd, mul=.2).out()
        flag = not(flag)
    elif key == Key.esc:
        s.stop()
        return False
    else:
        print('Wrong key:')
        print(keyStr)

class autoMusic:
    global am
    def __init__(self):
        self.freqs = midiToHz([60,62,64,65,67,69,71,72])
        self.rnd = Choice(choice=self.freqs, freq=[6,8])

if __name__ == '__main__':
    global am,flag
    flag = False
    fq = myfreq()
    fqdict = {'w':0, 'e':1, 'r':2, 's':3, 'd':4, 'f':5,
              'u':6, 'i':7, 'o':8, 'j':9, 'k':10, 'l':11}
    s = Server()
    s.setOutputDevice(8)
    s.boot()
    s.amp = 0.1
    s.start()
    ap = autoMusic()
    # amp = Fader(dur=1,mul=1).play()
    globalamp = Fader(fadein=2, fadeout=2, dur=0).play()
    env = Adsr(attack=0.005, decay=0.05, sustain=0.25, release=0.75, dur=1, mul=0.5)
    env.setExp(0.75)
    # am = Adsr(attack=0.01, decay=0.1, sustain=0.5, release=1.5, dur=2, mul=0.5)
    am = Sine(ap.rnd, mul=globalamp*env).out()
    with Listener(
            suppress = True,
            on_press = on_press) as listener:
        listener.join()


func = lambda x:x+5
print(func(5))

'''taking 2 values in lambda fn'''
func2=lambda x,y:x+y
print(func2(9,7))

"""there are map reduce and filter fn."""

l=[1,2,3,4,5]
l2=[]
for i in l:
    l2.append(i**2)
print(l2)

"""second way """

l=[1,2,3,4,5]
l2=[x**2 for x in l]
print(l2)

'''using map'''
print('map')

l=[1,2,3,4,5]
l2=list(map(lambda x:x**2,l))
print(l2)

l=[1,2,3,4,5,6,7]
l2=[]
for i in l:
    if i%2==1:
        l2.append(i)
print(l2)

l2=[x for x in l if x%2==1]
print(l2)

'''using filter'''
print('filter')
l2=list(filter(lambda x:x%2==1,l))
print(l2)


#!/usr/bin/python
"""
Electobot
by Philip Brien (http://github.com/ZsigE)

Analysis and prediction tool based on the 2010 UK General Election results

Data visualisation tools
"""

# Python imports
from operator import itemgetter, attrgetter
import os
import logging

# Third-party imports
import matplotlib.pyplot as plt
import numpy as np

# Electobot imports
import electobot.pollscrape as pollscrape
from electobot.constants import *

# Set up logging
logger = logging.getLogger("electobot.electoplot")

def create_pie_chart(results, filepath):
    """Generate a pie chart based on the results for a single election, and
    save it in the requested location.  Note that 'filepath' should not include
    the filetype suffix."""

    # Convert the results dictionary into arrays for matplotlib.
    items = sorted(results.iteritems(), key=itemgetter(1), reverse=True)
    partynames = [item[0] for item in items]
    numofseats = [item[1] for item in items]
    colours = [PARTY_COLOURS[party] for party in partynames]

    # Generate the chart.
    plt.figure(figsize=(8, 8))
    ptch, txts = plt.pie(numofseats,
                         labels=partynames,
                         colors=colours)
    for txt in txts:
        txt.set_size("small")

    # Save it off!
    filename = "{0}.png".format(filepath)
    plt.savefig(filename)

    return

def create_line_range_chart(savedpolls,
                            filepath,
                            pollsters=None,
                            sponsors=None,
                            min_sample_size=None,
                            start_date=None,
                            end_date=None):
    """Generate a line chart from a series of pollscrape Polls, with dates along
    the x-axis, and one line per party.  Also error bars for each result's 95%
    confidence intervals."""

    # Order the results by date.
    polls = sorted(savedpolls, key=attrgetter("date"))
    logger.info("Found {0} results, first from {1}, last from {2}".
                format(len(polls), polls[0].date, polls[-1].date))

    # Select the polls we want based on the various filter critera specified.
    # Assume that the poll is going to be included unless filtered out.
    polls_to_chart = []
    for poll in polls:
        if pollsters is not None and poll.pollster not in pollsters:
            logger.debug("Poll filtered out on pollster ({0})".
                         format(poll.pollster))
            continue
        elif sponsors is not None and poll.sponsor not in sponsors:
            logger.debug("Poll filtered out on sponsor ({0})".
                         format(poll.sponsor))
            continue
        elif min_sample_size is not None and poll.sample_size < min_sample_size:
            logger.debug("Poll filtered out on sample size ({0})".
                         format(poll.sample_size))
            continue
        elif start_date is not None and poll.date < start_date:
            logger.debug("Poll filtered out by start date ({0})".
                         format(poll.date))
            continue
        elif end_date is not None and poll.date > end_date:
            logger.debug("Poll filtered out by end date ({0})".
                         format(poll.date))
            continue
        else:
            polls_to_chart.append(poll)

    # Generate the various arrays that we'll need to plot these results.
    dates = [poll.date for poll in polls_to_chart]
    party_mean_seats = {}
    party_seat_error = {}
    for party in PARTY_NAMES:
        party_mean_seats[party] = []
        party_seat_error[party] = []
    for poll in polls_to_chart:
        for party in PARTY_NAMES:
            party_mean_seats[party].append(poll.result.mean_seats[party])

            # Error bars will be at +-2*standard deviation, as this gives us 95%
            # confidence intervals.
            party_seat_error[party].append(2 * poll.result.stddev_seats[party])

    # Create axes on which to put this information.
    axes = plt.subplot(1, 1, 1)

    # Generate points with error bars for all parties.  Suppress the line, as
    # this is misleading or multiple polls from the same day, but add markers
    # instead.
    for party in PARTY_NAMES:
        logger.debug("Adding line for {0}".format(party))
        logger.debug("  Line colour: {0}".format(PARTY_COLOURS[party]))
        axes.errorbar(dates,
                      party_mean_seats[party],
                      yerr=party_seat_error[party],
                      color=PARTY_COLOURS[party],
                      linestyle="None",
                      marker=".",
                      label=party)

    # Tweak the axis limits to ensure the y-axis starts at 0 and there's a gap
    # after the last results (scaled down for fewer results).
    limits = list(plt.axis())
    limits[1] += min(10, len(polls)/300.0)
    limits[2] = 0
    plt.axis(limits)

    # Rotate the x-axis labels to stop them clashing.
    locs, labels = plt.xticks()
    plt.setp(labels, rotation=45)

    # Add a horizontal line at the winning mark.
    plt.axhline(NEEDED_FOR_MAJORITY, color="black", linewidth=1)

    # Add a legend.
    plt.legend(loc="upper center",
               ncol=3,
               numpoints=1,
               bbox_to_anchor=(0.5, 1.16))

    # Increase the size of the figure to accommodate these elements.
    fig = plt.gcf()
    fig.set_size_inches(10, 8)
    fig.subplots_adjust(bottom=0.15, top=0.85)

    # Add a credit line (remove this if you're forking the code, obviously)
    fig.text(0.99, 0.01,
             "Generated by Electobot (http://github.com/ZsigE/electobot)",
             size="small", color="Black", ha="right")

    # Save off the chart.
    filename = "{0}.png".format(filepath)
    plt.savefig(filename)

    return

def create_poll_summary_barchart(mc_results, filepath):
    """Generate a bar chart with error bars to summarise the results of a
    Monte Carlo simulation.  Note that 'filepath' should not include the
    filetype suffix."""

    # Convert the MonteCarlo results into Matplotlib arrays.
    x_indices = range(len(mc_results.mean_seats))
    parties_seats = sorted(mc_results.mean_seats.items(),
                           key=itemgetter(1),
                           reverse=True)
    parties = [item[0] for item in parties_seats]
    seat_nums = [item[1] for item in parties_seats]
    errors = [2 * mc_results.stddev_seats[party] for party in parties]
    colours = [PARTY_COLOURS[party] for party in parties]

    # Create some axes and plot the data.
    axes = plt.subplot(1, 1, 1)
    axes.bar(x_indices, seat_nums, color=colours, yerr=errors, width=1,
             ecolor="Black")

    # Add a horizontal line at the winning mark.
    plt.axhline(NEEDED_FOR_MAJORITY, color="black", linewidth=1)

    # Tweak the axes - the y-axis starts at 0, and the x-axis labels are the
    # party names.
    plt.ylim(ymin=0)
    plt.xticks([num + 0.5 for num in x_indices], parties, size="x-small")
    plt.tick_params(bottom="off")

    # Add a credit line (remove this if you're forking the code, obviously)
    fig = plt.gcf()
    fig.text(0.99, 0.01,
             "Generated by Electobot (http://github.com/ZsigE/electobot)",
             size="small", color="Black", ha="right")

    # Save off the chart.
    filename = "{0}.png".format(filepath)
    plt.savefig(filename)

    return


import re

class CodeModel():
    """Model (data) for the code image"""

    def __init__(self, listings):

        # Member variable initialization.
        self.instr_lookup = {}

        # Add each file to the list of raw code lines.
        raw_lines = []
        for listing in listings:
            with open(listing, 'r') as f:
                raw_lines.extend(f.readlines())

        # Process the raw text to extract the instruction pointers
        # and build a lookup table indexed by an instruction pointer.
        self.labeled_code = []
        for line_number, line_text in enumerate(raw_lines):
            # Determine if the line text begins with an
            #instruction pointer.
            re_instr_ptr = re.match(r'^\s*([0-9a-fA-F]+):', line_text)
            label = 'src'
            if re_instr_ptr:
                instr_ptr = re_instr_ptr.group(1)
                self.instr_lookup[instr_ptr] = line_number
                label = 'asm'
            new_code = {'label': label, 'code': line_text}
            self.labeled_code.append(new_code)

    def get_labeled_code(self):
        return self.labeled_code

    def get_line_from_instr_ptr(self, instr_ptr):
        """Look up the code line number with instruction pointer"""
        line = None
        if instr_ptr in self.instr_lookup:
            line = self.instr_lookup[instr_ptr]
        return line


from .drug_encoder_v2 import DrugEncoderV2
from .feature_encoder import FeatureEncoder
import prep.utils as utils
import numpy as np

class PatientEncoder:
    def __init__(self, *,
                 duration_from_admission_in_hours=48,

                 max_number_of_drug_features=None,
                 # num_drug_features=2500,

                 max_num_of_diagnoses=1000,
                 min_frequency_of_diag=3,

                 include_age_at_admission=True,

                 max_number_admission_type_features=100,
                 min_frq_admission_type_features=3,

                 max_number_admission_location_features=100,
                 min_frq_admission_location_features=3,

                 max_number_insurance_features=100,
                 min_frq_insurance_features=3,

                 min_frq_marital_features=100,
                 max_number_marital_features=3):

        self.duration_from_admission_in_hours = duration_from_admission_in_hours
        self.max_number_of_drug_features = max_number_of_drug_features
        # self.num_drug_features = num_drug_features
        self.max_num_of_diagnoses = max_num_of_diagnoses
        self.min_frequency_of_diag = min_frequency_of_diag
        self.include_age_at_admission = include_age_at_admission

        self.max_number_admission_type_features = max_number_admission_type_features
        self.min_frq_admission_type_features = min_frq_admission_type_features

        self.max_number_admission_location_features = max_number_admission_location_features
        self.min_frq_admission_location_features = min_frq_admission_location_features

        self.max_number_insurance_features = max_number_insurance_features
        self.min_frq_insurance_features = min_frq_insurance_features

        self.max_number_marital_features = max_number_marital_features
        self.min_frq_marital_features = min_frq_marital_features

        self.drug_enc = DrugEncoderV2(duration_from_admission_in_hours=self.duration_from_admission_in_hours,
                                    max_number_of_drug_features=self.max_number_of_drug_features)

        self.diag_enc = FeatureEncoder('DIAGNOSIS',
                                       self.min_frequency_of_diag,
                                       self.max_num_of_diagnoses)

        self.adm_type_enc = FeatureEncoder('ADMISSION_TYPE',
                                           self.min_frq_admission_type_features,
                                           self.max_number_admission_type_features)

        self.adm_loc_enc = FeatureEncoder('ADMISSION_LOCATION',
                                          self.min_frq_admission_location_features,
                                          self.max_number_admission_location_features)

        self.insur_enc = FeatureEncoder('INSURANCE',
                                        self.min_frq_insurance_features,
                                        self.max_number_insurance_features)

        self.marital_enc = FeatureEncoder('MARITAL_STATUS',
                                          self.min_frq_marital_features,
                                          self.max_number_marital_features)

    def fit(self,
            prescriptions,
            admissions,
            patients):

        self.drug_enc.fit(prescriptions)
        self.diag_enc.fit(admissions)
        self.adm_type_enc.fit(admissions)
        self.adm_loc_enc.fit(admissions)
        self.insur_enc.fit(admissions)
        self.marital_enc.fit(admissions)

    def transform(self, prescriptions, admissions, patients):
        drug, hadm_id_map = self.drug_enc.transform(prescriptions, admissions)
        diag = self.diag_enc.transform(admissions, hadm_id_map)

        age = utils.get_age_at_admission(admissions, patients, hadm_id_map) / 100  # For normalization
        adm_type = self.adm_type_enc.transform(admissions, hadm_id_map)
        adm_loc = self.adm_loc_enc.transform(admissions, hadm_id_map)
        insur = self.insur_enc.transform(admissions, hadm_id_map)
        marital = self.marital_enc.transform(admissions, hadm_id_map)

        x = np.concatenate((drug,
                            diag,
                            adm_type,
                            adm_loc,
                            insur,
                            marital,
                            age,
                            ),
                            axis=1)
        return x, hadm_id_map


class Complex:
    def __init__(self, real=0, imag=0):
        self.real = real
        self.imag = imag

    def __add__(self, other):
        real_part = self.real + other.real
        imag_part = self.imag + other.imag
        return Complex(real_part, imag_part)

    def __str__(self):
        return f"{self.real} + {self.imag}i"
# Create two Complex objects
ca = Complex(-2, -5)
cb = Complex(12, 8)
# Display the calculation and result
print(ca, '+', cb, '=', (ca + cb))
# Display the type and memory address of ca
print('\n',type(ca), id(ca), '\n')
# Create an empty list to store Complex numbers
complex_list = []
# Read the number of Complex numbers to add
n = int(input("How many complex numbers you want to add:"))
# Loop to input and store the Complex numbers
for i in range(n):
    r = float(input("Enter the real part of the complex number: "))
    im = float(input("Enter the imaginary part of the complex number:"))
    print()
    complex_list.append(Complex(r, im))
# Initialize a Complex object to hold the sum
sum_series = Complex()
# Loop to calculate the sum of Complex numbers in the list
for j in complex_list:
    sum_series += j

# Display the sum of the Complex numbers
print("\nThe sum of the given Complex numbers is:", sum_series)


# -*- coding: utf-8 -*-
import json
import uuid

from django.contrib.admin.views.decorators import staff_member_required
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, HttpResponse
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.views.generic import FormView

from core import get_quote, get_order, copy_pages, insert_response, prepare_data, prepare_order_data
from models import TranslationRequest, TranslationResponse
from forms import AddTranslationForm, SelectPluginsByTypeForm
from utils import check_stage, is_dev, log_to_file, log_to_file_enabled

class AddTranslationView(FormView):
    template_name = 'aldryn_translator/add_translation.html'
    form_class = AddTranslationForm
    trans_pk = ''

    @method_decorator(staff_member_required)
    def dispatch(self, *args, **kwargs):
        return super(AddTranslationView, self).dispatch(*args, **kwargs)

    def get_success_url(self):
        return reverse('admin:select_plugins_by_type', kwargs={'pk': self.trans_pk})

    def form_valid(self, form):
        f = form.save(commit=False)
        f.from_lang = form.cleaned_data['from_lang']
        f.to_lang = form.cleaned_data['to_lang']
        f.provider = form.cleaned_data['provider']
        f.copy_content = form.cleaned_data['copy_content']
        f.all_stacks = form.cleaned_data['all_static_placeholders']
        f.save()
        f.pages = form.cleaned_data['pages']
        f.save()

        self.trans_pk = f.pk

        return super(AddTranslationView, self).form_valid(form)

@staff_member_required
def select_plugins_by_type_view(request, pk):
    t = TranslationRequest.objects.get(pk=pk)
    check_stage(t.status, 'draft')

    data = prepare_data(t, t.from_lang, t.to_lang)
    plugins = {}
    for p in data['Groups']:
        if p['Context'] == '_pagetitle':
            context = "Page Titles"
        else:
            context = p['Context']
        if context not in plugins:
            plugins[context] = 0
        plugins[context] += 1

    form = SelectPluginsByTypeForm(request.POST or None, plugins=plugins)

    if request.POST:
        if form.is_valid():
            t.order_selection = form.cleaned_data['plugins']
            t.status = 'selected_content'
            t.save()
            return redirect(reverse('admin:get_quote', kwargs={'pk': t.pk}))
    else:
        return render_to_response(
            'aldryn_translator/select_plugins_by_type.html',
            {'form': form}, context_instance=RequestContext(request)
        )

@staff_member_required
def select_plugins_by_id_view(request, pk):
    t = TranslationRequest.objects.get(pk=pk)
    check_stage(t.status, 'draft')

    if request.method == 'POST':
        raise NotImplementedError()
        t.status = 'selected_content'
        t.save()

    else:
        data = prepare_data(t, t.from_lang, t.to_lang)
        return render_to_response(
            'aldryn_translator/select_plugins_by_id.html', {'groups': data['Groups']},
            context_instance=RequestContext(request))

@staff_member_required
def get_quote_view(request, pk):
    t = TranslationRequest.objects.get(pk=pk)
    check_stage(t.status, 'selected_content')

    if request.method == 'POST':
        if request.POST.get('opt'):
            t.order_choice = request.POST.get('opt')  # TODO: possible security issue?
            t.status = 'selected_quote'
            t.save()
            return HttpResponseRedirect(reverse('admin:order', kwargs={'pk': pk}))

    else:
        data = prepare_data(t, t.from_lang, t.to_lang)
        quote = get_quote(t.provider, data=data)
        if log_to_file_enabled():
            log_to_file(data)
        if t.provider == 'supertext':
            res = json.loads(quote)
            return render_to_response(
                'aldryn_translator/quote.html', {'res': res, 'dev': is_dev()},
                context_instance=RequestContext(request))

        else:
            raise NotImplementedError()

@staff_member_required
def order_view(request, pk):
    t = TranslationRequest.objects.get(pk=pk)
    check_stage(t.status, 'selected_quote')

    t.reference = "%s-%s" % (str(pk), str(uuid.uuid4()))
    t.order_name = "Aldryn Translator Order"

    # COPY OLD LANG PAGE TREE TO NEW ONE
    if t.copy_content:
        copy_pages(t.from_lang, t.to_lang, t.pages)

    data = prepare_data(t, t.from_lang, t.to_lang, plugin_source_lang=t.to_lang)
    data.update(prepare_order_data(request, t))
    order = json.loads(get_order(t.provider, data))

    if log_to_file_enabled():
        log_to_file(data)

    t.sent_content = json.dumps(data, ensure_ascii=False).encode('ascii', 'xmlcharrefreplace')
    t.status = 'requested'
    t.save()

    # TODO: save other stuff from response to model (deadline, price, more?)

    if t.provider == 'supertext':
        return render_to_response(
            'aldryn_translator/confirmation.html', {'r': order},
            context_instance=RequestContext(request))

    else:
        raise NotImplementedError()

@csrf_exempt
def process_response(request):
    response = json.loads(request.body)

    trans_resp = TranslationResponse()
    trans_resp.received_content = response

    try:
        pk = response['ReferenceData'].partition("-")[0]
        trans_req = TranslationRequest.objects.get(pk=pk)
    except TranslationRequest.DoesNotExist:
        trans_resp.debug_info = "Translation Request with this PK could not be found"
        trans_resp.valid = False
        trans_resp.save()
        return HttpResponse(status=500, content="fail (1)")

    if not trans_req.status == 'requested':
        trans_resp.debug_info = "Translation Request's status is not valid for this step."
        trans_resp.valid = False
        trans_resp.save()
        return HttpResponse(status=500, content="fail (2)")

    if not trans_req.reference == response['ReferenceData']:
        trans_resp.debug_info = "Translation Request's ReferenceData does not match the one from the response!"
        trans_resp.valid = False
        trans_resp.save()
        trans_req.status = 'failed'
        return HttpResponse(status=500, content="fail (3)")

    trans_resp.valid = True
    trans_resp.request = trans_req
    trans_req.status = 'done'
    trans_resp.save()

    insert_response(trans_req.provider, response)

    return HttpResponse()