import logging
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from db.database import get_db
from db import models
from auth.jwt_bearer import JWTBearer
import uuid
from datetime import datetime, date
import schemas

from dependencies.profiles import get_active_profile_by_id
from dependencies.songs import get_user_and_his_song_by_id
from utils import strings, emailutil

app = APIRouter()

@app.get("/licence", tags=["licence"], dependencies=[Depends(JWTBearer())])
async def licence(song_id: uuid.UUID, user_id: uuid.UUID, db: Session = Depends(get_db)):
    try:
        get_artist = db.query(models.Songs, models.User_details).join(models.User_details, isouter=True).filter(
            models.Songs.id == song_id).filter(
            models.User_details.active_status == 0).first()
        if get_artist is not None:
            details = db.query(models.Licence).filter(models.Licence.user_id == user_id).filter(
                models.Licence.song_id == song_id).first()
            if details is not None:
                get_user = db.query(models.User_details).filter(models.User_details.id == user_id).first()

                project_response = {}
                if details.project_id is not None:
                    project_data = db.query(models.Projects, models.Project_Types).join(models.Project_Types,
                                                                                isouter=True).filter(
                        models.Projects.id == details.project_id).first()

                    project = project_data['Projects']
                    project_type = project_data['Project_Types']

                    project_response = {
                        "id": project.id,
                        "name": project.name,
                        "description": project.description,
                        "project_type_id": project_type.id if project_type else "",
                        "project_type": project_type.name if project_type else "",
                        "type_cost": project_type.cost if project_type else ""

                    }

                result = {
                    "artist_name": get_user.full_name,
                    "id": details.id,
                    "user_id": details.user_id,
                    "song_id": details.song_id,

                    "date": details.date,
                    "email": details.email,
                    "label": details.label,
                    "percentage": details.percentage,
                    "writers": details.writers,
                    "publishers": details.publishers,
                    "fee": details.fee,
                    "use": details.use,
                    "supervisor_invoice_info": details.supervisor_invoice_info,

                    "step": details.step,
                    "is_finished": details.is_finished,
                    "licence_agreement": details.licence_agreement,
                    "payment_status": details.payment_status,
                    "status": details.status,
                    "approved_date": details.approved_date,
                    "project": project_response
                }
                return {"status": "success", "response": result}
            else:
                data = db.query(models.Songs, models.User_details).join(models.User_details, isouter=True).filter(
                    models.Songs.id == song_id).first()
                if data is not None:
                    writer_names = []
                    publisher_names = []
                    for writer in data['Songs'].writers:
                        name = writer['writerName']
                        writer_names.append(name)
                    for publisher in data['Songs'].publishers:
                        name = publisher['publisherName']
                        publisher_names.append(name)
                    supervisor = db.query(models.User_details).filter(models.User_details.id == user_id).first()
                    licence_details = {
                        "date": date.today().strftime("%m/%d/%Y"),
                        "email": data['User_details'].email,
                        "performed_by": data['User_details'].full_name,
                        "to": data['User_details'].legal_name,
                        "songid": data['Songs'].id,
                        "own_recording": data['Songs'].own_recording,
                        "master_recording": data['Songs'].music_title,
                        "supervisor_name": supervisor.full_name,
                        "supervisor_id": supervisor.id,
                        "written_by": writer_names,
                        "published_by": publisher_names,
                        "label": data['Songs'].music_title
                    }
                    return {"status": "success", "response": licence_details}
        else:
            logging.info(
                "Data Not Found", exc_info=True
            )
            return {
                "status": "failed",
                "response": "Data Not Found",
            }
    except:
        logging.error("Exception occurred. Unable to get song details", exc_info=True)

# @app.get("/get_licences", tags=["licence"], dependencies=[Depends(JWTBearer())])
# async def get_licences(user_id: uuid.UUID, db: Session = Depends(get_db)):
#     active_user = await get_active_profile_by_id(user_id, db)
#
#     try:
#         licence_details = db.query(models.Licence).filter(models.Licence.user_id == user_id)
#
#         if not licence_details:
#             logging.info("Licenses for user does not exist", exc_info=True)
#             return {
#                 "status": "failed",
#                 "response": "Project for this user does not exist"
#             }
#         return {"status": "success", "response": licence_details}
#
#     except:
#         logging.error(strings.BASE_SONG_ERROR, exc_info=True)
#         raise HTTPException(
#             status_code=404,
#             detail=strings.BASE_SONG_ERROR
#         )

def _is_license_is_finished(license):
    if license.licence_agreement and license.step == 3:
        return True
    else:
        return False

# save licence details
@app.patch("/licence_agreement", tags=["licence"], dependencies=[Depends(JWTBearer())])
async def create_licence_agreement(user_data: schemas.Licence_data, db: Session = Depends(get_db)):
    song = await get_user_and_his_song_by_id(user_data.user_id, user_data.song_id, db)

    try:
        if song:
            licence_details = db.query(models.Licence).filter(models.Licence.user_id == user_data.user_id).filter(
                models.Licence.song_id == user_data.song_id).first()

            today_date = date.today().strftime("%m/%d/%Y")

            if licence_details is None:
                project_upd_data = user_data.project

                # if user_data.project_id and user_data.project_type_id:
                if project_upd_data:
                    project = db.query(models.Projects).filter(models.Projects.id == project_upd_data.get('id')).first()

                    if project:
                        update_data = {
                            "project_type_id": project_upd_data.get('project_type_id'),
                            "description": project_upd_data.get("description")
                        }
                        for name, value in update_data.items():
                            setattr(project, name, value)
                        db.add(project)
                        db.commit()
                        db.refresh(project)
                        logging.info("project updated successfully", exc_info=True)
                    logging.info("project not find", exc_info=True)

                id = uuid.uuid4()

                licence_data = models.Licence(
                    id=id,
                    user_id=user_data.user_id,
                    song_id=user_data.song_id,
                    project_id=project_upd_data.get("id") if project_upd_data else None,

                    label=user_data.label,
                    email=user_data.email,
                    percentage=user_data.percentage,
                    writers=user_data.writers,
                    publishers=user_data.publishers,

                    date=today_date,

                    fee=user_data.fee,
                    use=user_data.use,
                    supervisor_invoice_info=user_data.supervisor_invoice_info,

                    step=0,
                    is_finished=False if user_data.licence_agreement is False else True,
                    payment_status=False,
                    status=user_data.status
                )
                db.add(licence_data)
                db.commit()

                # add same details to notification table
                # TODO: CHECK WHEN YOU WILL WORK ON NOTIFICATIONS
                # id2 = uuid.uuid4()
                # today_date = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
                # notification_data = models.Notification(
                #     id=id2,
                #     user_id=user_data.user_id,
                #     song_id=user_data.song_id,
                #     datetime=today_date,
                #     date=date.today(),
                #     artist_id=user_data.artist_id,
                #     music_title=user_data.label,
                #     track_id=user_data.track_id,
                #     status=user_data.status)
                # db.add(notification_data)
                # db.commit()
                # like_details = db.query(models.Count_likes).filter(
                #     models.Count_likes.song_id == user_data.song_id).first()
                # if like_details is not None:
                #     a = {"user_id": str(user_data.user_id), "like": "True", "dislike": "False"}
                #     new_action = list(like_details.action)
                #     new_action.append(a)
                #     update_data = {"action": new_action}
                #     for name, value in update_data.items():
                #         setattr(like_details, name, value)
                #     db.add(like_details)
                #     db.commit()
                # else:
                #     new_action = []
                #     action = {"user_id": str(user_data.user_id), "like": "True", "dislike": "False"}
                #     new_action.append(action)
                #     song_data = models.Count_likes(
                #         id=id,
                #         song_id=user_data.song_id,
                #         action=new_action
                #     )
                #     db.add(song_data)
                #     db.commit()

                db.refresh(licence_data)
                await license_email(song)

                return {"status": "success", "response": licence_data}

            # elif licence_details and not _is_license_is_finished(licence_details):
            #     pass
            else:

                # if user_data.project_id and user_data.project_type_id:
                #     project = db.query(models.Projects).filter(models.Projects.id == user_data.project_id).first()
                #     update_project = {"project_type_id": user_data.project_id}
                #
                #     for name, value in update_project.items():
                #         setattr(project, name, value)
                #     db.add(project)
                #     db.commit()
                #     logging.info("project updated successfully", exc_info=True)
                #
                # elif user_data.project_id:
                #     pass

                project_upd_data = user_data.project

                # if user_data.project_id and user_data.project_type_id:
                if project_upd_data:
                    project = db.query(models.Projects).filter(models.Projects.id == project_upd_data.get('id')).first()

                    if project:
                        update_data = {
                            "project_type_id": project_upd_data.get('project_type_id'),
                            "description": project_upd_data.get("description")
                        }
                        for name, value in update_data.items():
                            setattr(project, name, value)
                        db.add(project)
                        db.commit()
                        db.refresh(project)
                        logging.info("project updated successfully", exc_info=True)
                    logging.info("project not find", exc_info=True)

                licence_data = {
                    "song_id": user_data.song_id,
                    "project_id": project_upd_data.get("id") if project_upd_data else None,

                    "label": user_data.label,
                    "email": user_data.email,
                    "percentage": user_data.percentage,
                    "writers": user_data.writers,
                    "publishers": user_data.publishers,

                    "date": today_date,

                    "fee": user_data.fee,
                    "use": user_data.use,
                    "supervisor_invoice_info": user_data.supervisor_invoice_info,

                    "step": user_data.step,
                    "is_finished": False if user_data.licence_agreement is False else True,
                    "payment_status": False,
                    "status": user_data.status
                }
                for name, value in licence_data.items():
                    setattr(licence_details, name, value)

                db.add(licence_details)
                db.commit()
                db.refresh(licence_details)

                await license_email(song)
                return {"status": "success", "response": licence_details}

        else:
            return {
                "status": "failed",
                "response": "Licence for this song for the supervisor already exists",
            }

    except:
        logging.error("Exception occurred. Unable to store licence details", exc_info=True)

# licence approval
@app.patch("/licence_applied", tags=["licence"], dependencies=[Depends(JWTBearer())])
async def apply_licence(apply_licence: schemas.Apply_licence, db: Session = Depends(get_db)):
    try:
        get_artist = db.query(models.Songs, models.User_details).join(models.User_details, isouter=True).filter(
            models.Songs.id == apply_licence.song_id).filter(
            models.User_details.active_status == 0).first()
        if get_artist is not None:
            user_data = (
                db.query(models.Licence)
                    .filter(models.Licence.user_id == apply_licence.user_id).filter(
                    models.Licence.song_id == apply_licence.song_id)
                    .first()
            )
            if user_data is not None:
                compare = date.today() - user_data.date
                if compare.days > 14:
                    updated_data = {
                        "status": 2
                    }
                    for name, value in updated_data.items():
                        setattr(user_data, name, value)
                    db.add(user_data)
                    db.commit()
                    return {
                        "status": "failed",
                        "response": "rejected"
                    }
                else:
                    update_data = {
                        "status": apply_licence.status,
                        "approved_date": date.today(),
                        "licensor": apply_licence.licensor,
                        "producer": apply_licence.producer
                    }
                for name, value in update_data.items():
                    setattr(user_data, name, value)
                db.add(user_data)
                db.commit()
                update_notification = (
                    db.query(models.Notification)
                        .filter(models.Notification.user_id == apply_licence.user_id).filter(
                        models.Notification.song_id == apply_licence.song_id)
                        .first()
                )
                update_value = {
                    "status": apply_licence.status,
                    "date": date.today(),
                    "seen": 0,
                    "datetime": datetime.now().strftime("%Y/%m/%d %H:%M:%S")
                }
                for name, value in update_value.items():
                    setattr(update_notification, name, value)
                db.add(update_notification)
                db.commit()
                today_date = date.today()
                invoice_data = models.Invoice(
                    supervisor_id=apply_licence.user_id,
                    song_id=apply_licence.song_id,
                    date=today_date,
                    Licence_id=user_data.id
                )
                db.add(invoice_data)
                db.commit()

                logging.info("status updated ", exc_info=True)
                return {
                    "status": "success",
                    "response": "status updated"
                }
            else:
                logging.info(
                    "status not updated", exc_info=True
                )
                return {
                    "status": "failed",
                    "response": "status not updated",
                }
        else:
            logging.info(
                "Data Not Found", exc_info=True
            )
            return {
                "status": "failed",
                "response": "Data Not Found",
            }
    except Exception:
        logging.error("Exception occurred.status cannot be update", exc_info=True)
        return {"status": "failed", "response": "status cannot be update"}

async def license_email(user_data):
    subject = f"Ktizo - {user_data.music_title} Registration Notification"

    emails = []

    if user_data.publishers:
        for x in user_data.publishers:
            if x.get('writerEmail'):
                emails.append(x.get('writerEmail'))

    if user_data.writers:
        for x in user_data.writers:
            if x.get('publisherEmail'):
                emails.append(x.get('publisherEmail'))

    recipient = emails
    message = f"""
    <!DOCTYPE html>

You're involved in the song {user_data.music_title} by {user_data.artist_title}, which will be on Ktizo's
    platform and potentially licensed to TV shows, movies, or commercials.

In accordance with the Song Registration Agreement, {user_data.artist_title} is responsible for distributing all
     royalties, fees, and other payments to other rightsholders of this song, including both the musical composition
      and sound recording.

If you approve of this song being licensed to TV shows, movies, or commercials, please click below:

If you do not click the approval button above, our Syncable application cannot match [SONG TITLE] to any
     projects.

If you have any questions or concerns, please contact us at music@ktizo.io.

Thank you,

Team at Ktizo

    """

    await emailutil.send_email(recipient, subject, message)


# coding: utf-8
import bpy
from . import vertexarray
from .. import bl
from pymeshio import englishmap

class Morph(object):
    __slots__=['name', 'type', 'offsets']
    def __init__(self, name, type):
        self.name=name
        self.type=type
        self.offsets=[]

    def add(self, index, offset):
        self.offsets.append((index, offset))

    def sort(self):
        self.offsets.sort(key=lambda e: e[0])

    def __str__(self):
        return "<Morph %s>" % self.name

class SSS(object):
    def __init__(self):
        self.use=1

class DefaultMaterial(dict):
    def __init__(self):
        self.name='default'
        # diffuse
        self.diffuse_color=[1, 1, 1]
        self.alpha=1
        # specular
        self.specular_toon_size=0
        self.specular_hardness=5
        self.specular_color=[1, 1, 1]
        # ambient
        self.mirror_color=[0, 0, 0]
        # flag
        self.subsurface_scattering=SSS()
        # texture
        self.texture_slots=[]

class OneSkinMesh(object):
    __slots__=['vertexArray', 'morphList', 'rigidbodies', 'constraints', 'armatureObj']
    def __init__(self):
        self.vertexArray=vertexarray.VertexArray()
        self.morphList=[]
        self.rigidbodies=[]
        self.constraints=[]
        self.armatureObj=None

    def __str__(self):
        return "<OneSkinMesh %s, morph:%d>" % (
                self.vertexArray,
                len(self.morphList))

    def build(self, node):
        ############################################################
        # search armature modifier
        ############################################################
        for m in node.o.modifiers:
            if bl.modifier.isType(m, 'ARMATURE'):
                armatureObj=bl.modifier.getArmatureObject(m)
                if not self.armatureObj:
                    self.armatureObj=armatureObj
                elif self.armatureObj!=armatureObj:
                    print("warning! found multiple armature. ignored.",
                            armatureObj.name)

        if node.o.type.upper()=='MESH':
            self.addMesh(node.o)

        for child in node.children:
            self.build(child)

    def addMesh(self, obj):
        if not bl.object.isVisible(obj):
            return
        self.__mesh(obj)
        self.__rigidbody(obj)
        self.__constraint(obj)

    def __getWeightMap(self, obj, mesh):
        # bone weight
        weightMap={}
        secondWeightMap={}
        def setWeight(i, name, w):
            if w>0:
                if i in weightMap:
                    if i in secondWeightMap:
                        # 上位２つのweightを採用する
                        if w<secondWeightMap[i][1]:
                            pass
                        elif w<weightMap[i][1]:
                            # ２つ目を入れ替え
                            secondWeightMap[i]=(name, w)
                        else:
                            # １つ目を入れ替え
                            weightMap[i]=(name, w)
                    else:
                        if w>weightMap[i][1]:
                            # 多い方をweightMapに
                            secondWeightMap[i]=weightMap[i]
                            weightMap[i]=(name, w)
                        else:
                            secondWeightMap[i]=(name, w)
                else:
                    weightMap[i]=(name, w)

        # ToDo bone weightと関係ないvertex groupを除外する
        for i, v in enumerate(mesh.vertices):
            if len(v.groups)>0:
                for g in v.groups:
                    setWeight(i, obj.vertex_groups[g.group].name, g.weight)
            else:
                try:
                    setWeight(i, obj.vertex_groups[0].name, 1)
                except:
                    # no vertex_groups
                    pass

        # 合計値が1になるようにする
        for i in range(len(mesh.vertices)):
            if i in secondWeightMap:
                secondWeightMap[i]=(secondWeightMap[i][0], 1.0-weightMap[i][1])
            elif i in weightMap:
                weightMap[i]=(weightMap[i][0], 1.0)
                secondWeightMap[i]=("", 0)
            else:
                print("no weight vertex")
                weightMap[i]=("", 0)
                secondWeightMap[i]=("", 0)

        return weightMap, secondWeightMap

    def __processFaces(self, obj_name, mesh, weightMap, secondWeightMap):
        default_material=DefaultMaterial()
        # 各面の処理
        for i, face in enumerate(mesh.tessfaces):
            faceVertexCount=bl.face.getVertexCount(face)
            try:
                material=mesh.materials[bl.face.getMaterialIndex(face)]
            except IndexError as e:
                material=default_material
            v=[mesh.vertices[index] for index in bl.face.getVertices(face)]
            uv=bl.mesh.getFaceUV(
                    mesh, i, face, bl.face.getVertexCount(face))

            if bl.face.isSmooth(face):
                if faceVertexCount==3:
                    self.__addFaceTriangleSmooth(
                            obj_name, material, v, uv,
                            weightMap, secondWeightMap
                            )
                elif faceVertexCount==4:
                    self.__addFaceQuadrangleSmooth(
                            obj_name, material, v, uv,
                            weightMap, secondWeightMap
                            )
            else:
                if faceVertexCount==3:
                    self.__addFaceTriangleSolid(
                            obj_name, material, v, uv,
                            bl.face.getNormal(face),
                            weightMap, secondWeightMap
                            )
                elif faceVertexCount==4:
                    self.__addFaceQuadrangleSolid(
                            obj_name, material, v, uv,
                            bl.face.getNormal(face),
                            weightMap, secondWeightMap
                            )

    def __addFaceTriangleSmooth(self, obj_name, material, v, uv,
            weightMap, secondWeightMap):
        self.vertexArray.addTriangle(
                obj_name, material.name,
                v[0].index,
                v[1].index,
                v[2].index,
                v[0].co,
                v[1].co,
                v[2].co,
                bl.vertex.getNormal(v[0]),
                bl.vertex.getNormal(v[1]),
                bl.vertex.getNormal(v[2]),
                uv[0],
                uv[1],
                uv[2],
                weightMap[v[0].index][0],
                weightMap[v[1].index][0],
                weightMap[v[2].index][0],
                secondWeightMap[v[0].index][0],
                secondWeightMap[v[1].index][0],
                secondWeightMap[v[2].index][0],
                weightMap[v[0].index][1],
                weightMap[v[1].index][1],
                weightMap[v[2].index][1]
                )

    def __addFaceQuadrangleSmooth(self, obj_name, material, v, uv,
            weightMap, secondWeightMap):
        self.vertexArray.addTriangle(
                obj_name, material.name,
                v[0].index,
                v[1].index,
                v[2].index,
                v[0].co,
                v[1].co,
                v[2].co,
                bl.vertex.getNormal(v[0]),
                bl.vertex.getNormal(v[1]),
                bl.vertex.getNormal(v[2]),
                uv[0],
                uv[1],
                uv[2],
                weightMap[v[0].index][0],
                weightMap[v[1].index][0],
                weightMap[v[2].index][0],
                secondWeightMap[v[0].index][0],
                secondWeightMap[v[1].index][0],
                secondWeightMap[v[2].index][0],
                weightMap[v[0].index][1],
                weightMap[v[1].index][1],
                weightMap[v[2].index][1]
                )
        self.vertexArray.addTriangle(
                obj_name, material.name,
                v[2].index,
                v[3].index,
                v[0].index,
                v[2].co,
                v[3].co,
                v[0].co,
                bl.vertex.getNormal(v[2]),
                bl.vertex.getNormal(v[3]),
                bl.vertex.getNormal(v[0]),
                uv[2],
                uv[3],
                uv[0],
                weightMap[v[2].index][0],
                weightMap[v[3].index][0],
                weightMap[v[0].index][0],
                secondWeightMap[v[2].index][0],
                secondWeightMap[v[3].index][0],
                secondWeightMap[v[0].index][0],
                weightMap[v[2].index][1],
                weightMap[v[3].index][1],
                weightMap[v[0].index][1]
                )

    def __addFaceTriangleSolid(self, obj_name, material, v, uv, normal,
            weightMap, secondWeightMap):
        # flip triangle
        self.vertexArray.addTriangle(
                obj_name, material.name,
                v[0].index,
                v[1].index,
                v[2].index,
                v[0].co,
                v[1].co,
                v[2].co,
                normal,
                normal,
                normal,
                uv[0],
                uv[1],
                uv[2],
                weightMap[v[0].index][0],
                weightMap[v[1].index][0],
                weightMap[v[2].index][0],
                secondWeightMap[v[0].index][0],
                secondWeightMap[v[1].index][0],
                secondWeightMap[v[2].index][0],
                weightMap[v[0].index][1],
                weightMap[v[1].index][1],
                weightMap[v[2].index][1]
                )

    def __addFaceQuadrangleSolid(self, obj_name, material, v, uv, normal,
            weightMap, secondWeightMap):
        self.vertexArray.addTriangle(
                obj_name, material.name,
                v[0].index,
                v[1].index,
                v[2].index,
                v[0].co,
                v[1].co,
                v[2].co,
                normal,
                normal,
                normal,
                uv[0],
                uv[1],
                uv[2],
                weightMap[v[0].index][0],
                weightMap[v[1].index][0],
                weightMap[v[2].index][0],
                secondWeightMap[v[0].index][0],
                secondWeightMap[v[1].index][0],
                secondWeightMap[v[2].index][0],
                weightMap[v[0].index][1],
                weightMap[v[1].index][1],
                weightMap[v[2].index][1]
                )
        self.vertexArray.addTriangle(
                obj_name, material.name,
                v[2].index,
                v[3].index,
                v[0].index,
                v[2].co,
                v[3].co,
                v[0].co,
                normal,
                normal,
                normal,
                uv[2],
                uv[3],
                uv[0],
                weightMap[v[2].index][0],
                weightMap[v[3].index][0],
                weightMap[v[0].index][0],
                secondWeightMap[v[2].index][0],
                secondWeightMap[v[3].index][0],
                secondWeightMap[v[0].index][0],
                weightMap[v[2].index][1],
                weightMap[v[3].index][1],
                weightMap[v[0].index][1]
                )

    def __mesh(self, obj):
        if bl.RIGID_SHAPE_TYPE in obj:
            return
        if bl.CONSTRAINT_A in obj:
            return

        bl.message("export: %s" % obj.name)

        # メッシュのコピーを生成してオブジェクトの行列を適用する
        copyMesh, copyObj=bl.object.duplicate(obj)
        copyObj.name="tmp_object"
        if len(copyMesh.vertices)>0:
            # apply transform
            copyMesh.transform(obj.matrix_world)
            if bl.object.hasShapeKey(copyObj):
                matrix=obj.matrix_world
                for key in copyMesh.shape_keys.key_blocks:
                    for point in key.data:
                        point.co=matrix*point.co
            copyMesh.calc_normals()

            # apply modifier
            for m in [m for m in copyObj.modifiers]:
                if m.type=='SOLIDFY':
                    continue
                elif m.type=='ARMATURE':
                    continue
                elif m.type=='MIRROR':
                    bpy.ops.object.modifier_apply(modifier=m.name)
                else:
                    print(m.type)

            # fix empty tessfaces(from blender2.66?)
            copyMesh.update(calc_tessface=True)

            weightMap, secondWeightMap=self.__getWeightMap(copyObj, copyMesh)
            self.__processFaces(obj.name, copyMesh, weightMap, secondWeightMap)
            self.__weights(copyObj, copyMesh, obj.name)
            self.__skin(copyObj, obj.name)
        bl.object.delete(copyObj)

    def createEmptyBasicSkin(self):
        self.__getOrCreateMorph('base', 0)

    def __skin(self, obj, obj_name):
        if not bl.object.hasShapeKey(obj):
            return

        indexRelativeMap={}
        blenderMesh=bl.object.getData(obj)
        baseMorph=None

        # shape keys
        vg=bl.object.getVertexGroup(obj, bl.MMD_SHAPE_GROUP_NAME)
        if len(vg)==0:
            vg=list(range(len(blenderMesh.vertices)))

        # base
        used=set()
        for b in bl.object.getShapeKeys(obj):
            if b.name==bl.BASE_SHAPE_NAME:
                baseMorph=self.__getOrCreateMorph('base', 0)
                basis=b

                relativeIndex=len(baseMorph.offsets)
                for index in vg:
                    v=bl.shapekey.getByIndex(b, index)
                    pos=[v[0], v[1], v[2]]

                    indices=self.vertexArray.getMappedIndex(obj_name, index)
                    for attribute, i in indices.items():
                        if i in used:
                            continue
                        used.add(i)

                        baseMorph.add(i, pos)
                        indexRelativeMap[i]=relativeIndex
                        relativeIndex+=1

                break
        assert(basis)
        #print(basis.name, len(baseMorph.offsets))

        if len(baseMorph.offsets)==0:
            return

        # shape keys
        for b in bl.object.getShapeKeys(obj):
            if b.name==bl.BASE_SHAPE_NAME:
                continue

            morph=self.__getOrCreateMorph(b.name, 4)
            used=set()
            for index, src, dst in zip(
                    range(len(blenderMesh.vertices)),
                    bl.shapekey.get(basis),
                    bl.shapekey.get(b)):
                offset=[dst[0]-src[0], dst[1]-src[1], dst[2]-src[2]]
                if offset[0]==0 and offset[1]==0 and offset[2]==0:
                    continue
                if index in vg:
                    indices=self.vertexArray.getMappedIndex(obj_name, index)
                    for attribute, i in indices.items():
                        if i in used:
                            continue
                        used.add(i)
                        morph.add(indexRelativeMap[i], offset)
            assert(len(morph.offsets)<=len(baseMorph.offsets))

        # sort skinmap
        original=self.morphList[:]
        def getIndex(morph):
            for i, v in enumerate(englishmap.skinMap):
                if v[0]==morph.name:
                    return i
            #print(morph)
            return len(englishmap.skinMap)
        self.morphList.sort(key=getIndex)

    def __rigidbody(self, obj):
        if not bl.RIGID_SHAPE_TYPE in obj:
            return
        self.rigidbodies.append(obj)

    def __constraint(self, obj):
        if not bl.CONSTRAINT_A in obj:
            return
        self.constraints.append(obj)

    def __getOrCreateMorph(self, name, type):
        for m in self.morphList:
            if m.name==name:
                return m
        m=Morph(name, type)
        self.morphList.append(m)
        return m

    def getVertexCount(self):
        return len(self.vertexArray.positions)

    def __weights(self, obj, mesh, obj_name):
        for v in mesh.vertices:
            for i in self.vertexArray.getMappedIndex2(obj_name, v.index):
                ext_w=self.vertexArray.ext_weight[i]
                ext_w.entries.extend( filter( lambda ent: not ent[0].startswith("_"), \
                    ((obj.vertex_groups[vg.group].name, vg.weight) for vg in v.groups) ) )


# write your solution here
if True:
    text = input("Write text: ")
else:
    text = "We use ptython to make a spell checker"

wordcheck = []
with open("wordlist.txt") as new_file:
    for line in new_file:
        line = line.strip()
        wordcheck.append(line)

# text2 = text.split()
# text3 = []
# for a in text2:
#     if a.lower() not in wordcheck:
#         a = f"*{a}*"
#     text3.append(a)

print(" ".join(text3))


# Chem Kit V2.0 - main.py
# Author: Finn Bear
# Date: December 6, 2016

#########
# Input #
#########

# Gassium [Ga] (A fictional gas)
gassium_particles_initial = 150 # How many gassium particles are in the simulation initially
gassium_rate = 0 # How many gassium particles to add or subtract each tick
gassium_radius = 5 # The radius of a gassium particle

# Brownium [Br] (A fictional particle for brownian motion)
brownium_particles_initial = 300 # How many brownium particles are in the simulation initially
brownium_rate = 0 # How many brownium particles to add or subtract each tick
brownium_radius = 1 # The radius of a brownium particle

############
# Settings #
############

# Physics
max_velocity = 2
gravity = 0

# Rendering
output_directory = "../out/"
length = 20 # Length of the video in seconds
width = 1000 # How many pixels wide is the video
height = 1000 # How many pixels tall is the video
ticks_per_frame = 1 # How many simulation updates per frame of video
frames_per_second = 10 # How many frames of video per second
background_color = "black" # The color of the background
overlay_title_text = "Particle Simulator" # The title text of the overlay
overlay_subtitle_text = "By Finn Bear" # The subtitle text of the overlay

###########
# Imports #
###########
import os
import math
import random
import datetime
import PIL
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw

#############
# Variables #
#############

# Physics
tick_counter = 0 # How many simulation updates have been made
particles = [] # Store the particles in the simulation

# Rendering
frame_counter = 0 # How many frames have been created

#############
# Constants #
#############

# Rendering
center_x = width / 2;
center_y = height / 2;
max_frames = length * frames_per_second # Number of frames to render in total
overlay_title_position = (5, 5) # Position of overlay title text
overlay_subtitle_position = (5, 15) # Position of overlay subtitle text
overlay_frames_position = (5, 25) # Position of frame counter

##########
# main() #
##########

def main():
	global ticks_per_frame
	global frams_per_second
	global tick_counter
	global frame_counter

	init()

	try:
		while True:
			t0 = datetime.datetime.now()
			tick()
			tick_counter += 1
			if frame_counter < max_frames:
				if tick_counter % ticks_per_frame == 0:
					draw()
					frame_counter += 1
			else:
				# Compile video
				os.system("yes y | ffmpeg -framerate " + str(frames_per_second) + " -i " + output_directory + "frame%05d.png -c:v libx264 -r 30 -pix_fmt yuv420p " + output_directory + "out.mp4")
				os.system("rm " + output_directory + "*.png")

				# Exit
				exit(0)
			t1 = datetime.datetime.now()

			print("Tick #" + str(tick_counter) + " took " + str(int((t1 - t0).total_seconds() * 1000)) + "ms")

	except KeyboardInterrupt:
		# Compile video
		os.system("yes y | ffmpeg -framerate " + str(frames_per_second) + " -i " + output_directory + "frame%05d.png -c:v libx264 -r 30 -pix_fmt yuv420p " + output_directory + "out.mp4")
		os.system("rm " + output_directory + "*.png")

		# Exit
		exit(0)

############
# Routines #
############

# Physics
def init():
	global center_x
	global center_y
	global particles
	global gassium_particles_initial
	global gassium_radius
	global brownium_particles_initial
	global brownium_radius

	# Clear the output directory to remove old frames
	for file in os.listdir(output_directory):
		path = os.path.join(output_directory, file)
		try:
		    if os.path.isfile(path) and "frame" in path:
		        os.unlink(path)
		except Exception as e:
		    print(e)

	# Create particles
	gassium_particles = []
	brownium_particles = []
	id = 0;
	for i in range(0, gassium_particles_initial):
		gassium_particles.append({'id': id, 'type': 'Ga', 'radius': gassium_radius, 'x': center_x, 'y': center_y, 'vx': 0, 'vy': 0})
		id += 1

	for i in range(0, brownium_particles_initial):
		brownium_particles.append({'id': id, 'type': 'Br', 'radius': brownium_radius, 'x': center_x, 'y': center_y, 'vx': 0, 'vy': 0})
		id += 1;

	# Add the new particles to the list of particles
	particles.extend(gassium_particles)
	particles.extend(brownium_particles)

def tick():
	global particles
	global center_x
	global center_y

	# A list to store the updated particles
	newParticles = []

	# Iterate throught the particles
	for particle1 in particles:
		newParticle = particle1
		for particle2 in particles:
			if particle1 != particle2:
				newParticle = physics(newParticle, particle2)
		newParticles.append(newParticle)

	# Put the new particles back into the list of particles
	particles = newParticles

def physics(particle1, particle2):
	distance = distanceParticles(particle1, particle2)
	angle = vecRadians(particle1["x"], particle1["y"], particle2["x"], particle2["y"])
	multiplier = 1 / (distance + 0.001);

	# Check if the particles intersect
	if distance < particle1["radius"] + particle2["radius"]:
		multiplier = 2 / (distance + 0.001);

	particle1["vx"] -= multiplier * math.cos(angle + (random.random() - 0.5))
	particle1["vy"] -= multiplier * math.sin(angle + (random.random() - 0.5))

	# <Hack>
	#cAngle = vecRadians(particle1["x"], particle1["y"], center_x, center_y)
	#particle1["vx"] += 1 * math.cos(cAngle + (random.random() - 0.5))
	#particle1["vy"] += 1 * math.sin(cAngle + (random.random() - 0.5))
	# </Hack>

	# Apply gravity
	particle1["y"] += gravity

	# Apply velocity
	particle1["x"] += particle1["vx"]
	particle1["y"] += particle1["vy"]

	# Constrain position
	particle1["x"] = clamp(particle1["x"], 0, width)
	particle1["y"] = clamp(particle1["y"], 0, height)

	# Constrain velocity
	particle1["vx"] = clamp(particle1["vx"], 0, max_velocity)
	particle1["vy"] = clamp(particle1["vy"], 0, max_velocity)

	return particle1

# Rendering
def draw():
	global particles
	global frame_counter
	global output_directory

	# Create a blank frame
	frame = Image.new( 'RGB', (width, height), background_color)

	# Load the pixels of the blank frame
	pixels = frame.load()

	# Render
	for particle in particles:
		pt = particle['type']
		px = int(particle['x'])
		py = int(particle['y'])
		pr = particle['radius']

		for x in range(int(px) - pr - 1, int(px) + pr + 1):
			for y in range(int(py) - pr - 1, int(py) + pr + 1):
				if inRect(x, y, 0, 0, frame.size[0] - 1, frame.size[1] - 1) and distance(x, y, particle['x'], particle['y']) <= particle['radius']:
					if (pt == "Ga"):
						pixels[x,y] = (0, 255, 255)
					elif (pt == "Br"):
						pixels[x,y] = (255, 255, 255)

	# Overlays
	overlay = ImageDraw.Draw(frame)
	overlay.text(overlay_title_position, overlay_title_text, (255,255,0))
	overlay.text(overlay_subtitle_position, overlay_subtitle_text, (255,255,0))
	overlay.text(overlay_frames_position, "Frame: #" + str(frame_counter), (255,255,0))

	# Save the frame
	frame.save(output_directory + "frame" + str(str(frame_counter).zfill(5)) + ".png")

#############
# Functions #
#############

# Math
def chance(probability):
	return random.random() < probability

def translate(value, leftMin, leftMax, rightMin, rightMax):
	leftSpan = leftMax - leftMin
	rightSpan = rightMax - rightMin
	valueScaled = float(value - leftMin) / float(leftSpan)

	return rightMin + (valueScaled * rightSpan)

def clamp(value, minimum, maximum):
	return max(minimum, min(maximum, value))

def distance(x1, y1, x2, y2):
	return math.hypot(x2 - x1, y2 - y1)

def distanceParticles(particle1, particle2):
	return math.hypot(particle2["x"] - particle1["x"], particle2["y"] - particle1["y"])

def inRect(x, y, bx1, by1, bx2, by2):
	return (bx1 <= x <= bx2 and by1 <= y <= by2) or (bx1 >= x >= bx2 and by1 >= y >= by2)

def vecRadians(x1, y1, x2, y2):
	angle = math.atan2(y1 - y2, x1 - x2);
	while (angle < 0):
		angle += math.pi;
	return angle

###########
# Program #
###########
main()


#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on Fri May 6 17:40:00 2014

@author: Chang Long Zhu Jin
@email: changlongzj@gmail.com
"""

import smach
import rospy

import smach_ros
from smach_ros import SimpleActionState, ServiceState

from reem_tabletop_grasping.msg import ObjectManipulationAction, ObjectManipulationActionGoal,ObjectManipulationActionResult, ObjectManipulationGoal
from object_recognition_msgs.msg import ObjectType, RecognizedObject, RecognizedObjectArray

OPERATION_PICK = 1
OPERATION_PLACE = 2
OBJECT_MANIPULATION_TOPIC = '/object_manipulation_server_dual_arms'
GROUP_NAME = 'right_arm_torso'

class Prepare_data(smach.State):
    def __init__(self, pose_to_place):
        smach.State.__init__(self,
                             outcomes = ['succeeded', 'aborted'],
                             input_keys = ['pose_to_place'],
                             output_keys = ['object_place_position'])
        self.object_position = pose_to_place

    def execute(self, userdata):
        if not self.object_position and not userdata.pose_to_place:
            rospy.logerr("No Object to Detect")
            return 'aborted'
        #Object Position is a PoseStamped
        userdata.object_place_position = self.object_position if self.object_position else userdata.pose_to_place

        return 'succeeded'

class Prepare_Place_Goal(smach.State):
    def __init__(self):
        smach.State.__init__(self,
                             outcomes = ['succeeded', 'aborted'],
                             input_keys = ['object_place_position'],
                             output_keys = ['object_manipulation_goal'])

    def execute(self, userdata):
        goal_to_send = ObjectManipulationGoal()
        goal_to_send.operation = ObjectManipulationGoal.PLACE
        goal_to_send.group = GROUP_NAME

        goal_to_send.target_pose = userdata.object_place_position

        userdata.object_manipulation_goal = goal_to_send

        return 'succeeded'

class place_object_sm(smach.StateMachine):
    def __init__(self, pose_to_place=''):
        smach.StateMachine.__init__(self,
                                    outcomes=['succeeded', 'preempted', 'aborted'],
                                    input_keys=['pose_to_place'],
                                    output_keys=[])
        with self:
            smach.StateMachine.add("Prepare_data",
                                   Prepare_data(pose_to_place),
                                   transitions={'succeeded':'Place_Object_Goal','aborted':'aborted'})

            smach.StateMachine.add('Place_Object_Goal',
                                   Prepare_Place_Goal(),
                                   transitions={'succeeded':'Place_Object'})

            smach.StateMachine.add('Place_Object',
                                SimpleActionState(OBJECT_MANIPULATION_TOPIC,
                                                   ObjectManipulationAction,
                                                   goal_key='object_manipulation_goal',
                                                   input_keys=['standard_error'],
                                                   output_keys=['standard_error']),
                                transitions={'succeeded':'succeeded', 'aborted':'aborted'})


"""
https://leetcode.com/problems/count-nice-pairs-in-an-array/
"""

from collections import Counter

class Solution:
    def countNicePairs(self, nums: list[int]) -> int:
        """
        nums[i] + revs[j] = nums[j] + revs[i] ==>
        nums[i] - revs[i] = nums[j] - revs[j] ==>
        Then we just need to find how many pairs having the same difference.
        """
        pairs = 0
        cnt = Counter()
        for x in nums:
            y = int(str(x)[::-1])
            pairs += cnt[x - y]
            cnt[x - y] += 1

        return pairs % (10 ** 9 + 7)

print(Solution().countNicePairs([42, 11, 1, 97]))


import database
from card import Card

def listCards(fileName):
    db = database.loadDatabase(fileName)
    cards = database.loadAllCards(db=db)
    for card in cards:
        print(str(card))

if __name__ == "__main__":
    db = database.loadDatabase("box.db")
    print("You can list/add/modify/delete")
    command = input("What to do: ").lower()
    if command == "list":
        print("Listing...")
        listCards("box.db")
    elif command == "add":
        question = input("Question: ")
        answer = input("answer: ")
        colour = input("colour: ")
        image = input("image: ")
        card = Card(
                None,
                question,
                answer,
                colour,
                image,
                1, 0)
        database.insertCard(db, card)
    elif command == "modify":
        cardId = input("Id of card to replace: ")
        card = database.loadCard(db, cardId)
        property_ = input("Property to modify: ").lower()
        value = input("New value: ")
        if property_ == "question":
            card.question = value
        elif property_ == "answer":
            card.answer = value
        elif property_ == "colour":
            card.colour = value
        elif property_ == "image":
            card.image = value
        database.replaceCard(db, cardId, card)
    elif command == "delete":
        cardId = input("Id of card to delete: ")
        database.deleteCard(db, cardId)
    else:
        print("Unrecognised command")


import numpy
import torch
import random

class ToTensor(object):
  """Convert ndarrays in sample to Tensors."""
  def __call__(self, sample):
    clip_len = len(sample)
    trans_clip = []
    for i in range(clip_len):
        trans_clip.append(torch.from_numpy(sample[i]))
    return trans_clip

class SpacialCrop(object):
  def __init__(self, crop_size=112, crop_position=None):
    self.crop_size = crop_size
    if crop_position is None:
      self.randomize = True
    else:
      self.randomize = False
      self.crop_position = crop_position
      self.crop_positions = ['c', 'tl', 'tr', 'bl', 'br']

  def __call__(self, sample):
    clip_len = len(sample)
    t, h, w, c = sample[0].shape
    assert h > self.crop_size, "Frame height is smaller than target crop size"
    assert w > self.crop_size, "Frame width is smaller than target crop size"

    if self.randomize == True:
      x1 = random.randint(0, w - self.crop_size)
      y1 = random.randint(0, h - self.crop_size)
    elif self.crop_position == 'c':
      x1 = (w - self.crop_size) // 2
      y1 = (h - self.crop_size) // 2
    elif self.crop_position == 'tl':
      x1 = 0
      y1 = 0
    elif self.crop_position == 'tr':
      x1 = w - self.crop_size
      y1 = 0
    elif self.crop_position == 'bl':
      x1 = 0
      y1 = h - self.crop_size
    elif self.crop_position == 'br':
      x1 = w - self.crop_size
      y1 = h - self.crop_size

    x2 = x1 + self.crop_size
    y2 = y1 + self.crop_size

    trans_clip = []
    for i in range(clip_len):
        trans_clip.append(self._crop_clip(sample[i], y1, y2, x1, x2))
    return trans_clip

  def _crop_clip(clip, y1, y2, x1, x2):
      return clip[:,y1:y2,x1:x2,:]


import pygame, math, sys

def refresh(screen, player, grid):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.MOUSEBUTTONUP:
            pos = pygame.mouse.get_pos()
            column = math.floor(pos[0] / 100)
            return _add_piece(grid, column, player)

    screen.fill((0, 128, 255))
    _draw_grid(screen, grid)
    pygame.display.update()

    return True

def _draw_grid(screen, grid):
    y = 50
    for row in grid:
        x = 50
        for cell in row:
            color = (0, 0, 0)
            if cell == 1:
                color = (255, 128, 0)
            elif cell == 2:
                color = (0, 255, 128)
            pygame.draw.circle(screen, color, (x, y), 40)
            x = x + 100
        y = y + 100

def _add_piece(grid, column, player):
    i = 5
    while i >= 0:
        if grid[i][column] == 0:
            grid[i][column] = player
            return False
        i = i - 1
    return True

def display_result(screen, outcome):
    font = pygame.font.Font("roboto.ttf", 32)
    text = font.render(f"You {outcome}", True, (0, 0, 0), (255, 255, 255))
    text_rect = text.get_rect()
    text_rect.center = (350, 300)
    screen.blit(text, text_rect)
    pygame.display.update()


import Downsampling.downsampling_data_distributions as ddd
from matplotlib import pyplot as plt
import matplotlib.mlab as mlab
import Recurrent_ANN.read_data as rd
import math
import numpy as np

def plot_downsample_norm_dists(data_range= None, fifty=False, decimate=False, resample=False, average=False, every_second=False):
    one_to_three_means, one_to_three_sigmas, labels = ddd.norm_dist_differences([0, 3], data_range=data_range, fifty=fifty, decimate=decimate, resample=resample, average=average, every_second=every_second)
    four_to_six_means, four_to_six_sigmas, labels  = ddd.norm_dist_differences([3, 6], data_range=data_range, fifty=fifty, decimate=decimate, resample=resample, average=average, every_second=every_second)

    x = np.arange(-1, 1, 0.01)

    for i in range(len(one_to_three_sigmas)):
        plt.plot(x, mlab.normpdf(x, one_to_three_means[i], one_to_three_sigmas[i]), label=labels[i]+"BACK?")
        plt.plot(x, mlab.normpdf(x, four_to_six_means[i], four_to_six_sigmas[i]), label=labels[i]+"THIGH?")

    plt.axvline(x=0, linestyle='--', color="Red")
    plt.legend()
    plt.show()

def plot_data_norm_dists(paths_to_data_folders):
    data_points_list = read_datapoints_to_list(paths_to_data_folders)
    print(data_points_list[0].shape)

    normal_mean_THIGH, normal_mean_BACK = get_sensor_mean(data_points_list[0])
    normal_var_THIGH, normal_var_BACK = get_sensor_variance(data_points_list[0])
    normal_sigma_THIGH = math.sqrt(normal_var_THIGH)
    normal_sigma_BACK = math.sqrt(normal_var_BACK)

    in_lab_mean_THIGH, in_lab_mean_BACK = get_sensor_mean(data_points_list[1])
    in_lab_var_THIGH, in_lab_var_BACK  = get_sensor_variance(data_points_list[1])
    in_lab_sigma_THIGH = math.sqrt(in_lab_var_THIGH)
    in_lab_sigma_BACK = math.sqrt(in_lab_var_BACK)

    x = np.arange(-2, 2, 0.01)

    plt.title("In Lab data vs Out of Lab data")
    plt.plot(x, mlab.normpdf(x, normal_mean_THIGH, normal_sigma_THIGH), label="out-of-lab_THIGH")
    plt.plot(x, mlab.normpdf(x, normal_mean_BACK, normal_sigma_BACK), label="out-of-lab_BACK")

    plt.plot(x, mlab.normpdf(x, in_lab_mean_THIGH, in_lab_sigma_THIGH), label="in-Lab_THIGH")
    plt.plot(x, mlab.normpdf(x, in_lab_mean_BACK, in_lab_sigma_BACK), label="in-Lab_BACK")
    plt.legend()
    plt.show()

def get_sensor_mean(datapoints):
    means = []
    for i in range(datapoints.shape[1]):
        means.append(np.mean(datapoints[:, i, :]))
    return means

def get_sensor_variance(datapoints):
    variances = []
    for i in range(datapoints.shape[1]):
        variances.append(np.var(datapoints[:, i, :]))

    return variances

def read_datapoints_to_list(list_of_folders):
    folder_datapoints = []

    for folder in list_of_folders:
        print(folder)
        datapoints, labels = rd.select_csv_files(folder)
        datapoints = rd.generate_examples_and_labels(datapoints, labels, 1, 20, print_stats=True, generate_labels=False)
        datapoints = np.reshape(datapoints, newshape=[datapoints.shape[0], datapoints.shape[2]])
        datapoints = np.reshape(datapoints,
                                newshape=[datapoints.shape[0], datapoints.shape[1] / (datapoints.shape[1] / 2),
                                          datapoints.shape[1] / 2])
        folder_datapoints.append(datapoints)

    return folder_datapoints

plot_data_norm_dists(["/home/guest/Documents/HAR-Pipeline/DATA/trene", "/home/guest/Documents/HAR-Pipeline/DATA/HUNT4-Training-Data-InLab-UpperBackThigh"])


'''
   Author: Rohith Kumar Punithavel
   Email: rohithkumar@asu.edu
   Problem Statement: https://leetcode.com/problems/peak-index-in-a-mountain-array/
'''

class Solution:
    def peakIndexInMountainArray(self, A: List[int]) -> int:
        for i in range(1,len(A)-1):
            if A[i-1]<A[i] and A[i]>A[i+1]:
                return i


from __future__ import unicode_literals
import ezdxf
# FILENAME = r'C:\Users\manfred\Desktop\Now\page_setup_R12.dxf'
FILENAME = 'page_setup_R12.dxf'

def draw_raster(dwg):
    marker = dwg.blocks.new(name='MARKER')
    attribs = {'color': 2}
    marker.add_line((-1, 0), (1, 0), dxfattribs=attribs)
    marker.add_line((0, -1), (0, 1), dxfattribs=attribs)
    marker.add_circle((0, 0), .4, dxfattribs=attribs)

    marker.add_attdef('XPOS', (0.5, -1.0), dxfattribs={'height': 0.25, 'color': 4})
    marker.add_attdef('YPOS', (0.5, -1.5), dxfattribs={'height': 0.25, 'color': 4})
    modelspace = dwg.modelspace()
    for x in range(10):
        for y in range(10):
            xcoord = x * 10
            ycoord = y * 10
            values = {
                'XPOS': "x = %d" % xcoord,
                'YPOS': "y = %d" % ycoord
            }
            modelspace.add_auto_blockref('MARKER', (xcoord, ycoord), values)

def setup_active_viewport(dwg):
    # delete '*Active' viewport configuration
    dwg.viewports.delete_config('*ACTIVE')
    # the available display area in AutoCAD has the virtual lower-left corner (0, 0) and the virtual upper-right corner
    # (1, 1)

    # first viewport, uses the left half of the screen
    viewport = dwg.viewports.new('*ACTIVE')
    viewport.dxf.lower_left = (0, 0)
    viewport.dxf.upper_right = (.5, 1)
    viewport.dxf.target_point = (0, 0, 0)  # target point defines the origin of the DCS, this is the default value
    viewport.dxf.center_point = (40, 30)  # move this location (in DCS) to the center of the viewport
    viewport.dxf.height = 15  # height of viewport in drawing units, this parameter works
    viewport.dxf.aspect_ratio = 1.0  # aspect ratio of viewport (x/y)

    # second viewport, uses the right half of the screen
    viewport = dwg.viewports.new('*ACTIVE')
    viewport.dxf.lower_left = (.5, 0)
    viewport.dxf.upper_right = (1, 1)
    viewport.dxf.target_point = (60, 20, 0)  # target point defines the origin of the DCS
    viewport.dxf.center_point = (0, 0)  # move this location (in DCS, model space = 60, 20) to the center of the viewport
    viewport.dxf.height = 15  # height of viewport in drawing units, this parameter works
    viewport.dxf.aspect_ratio = 2.0  # aspect ratio of viewport (x/y)

def layout_page_setup(dwg):
    # DXF R12 supports just one paper space layout
    layout = dwg.layout()
    layout.page_setup(size=(11, 8.5), margins=(1, 2, 1, 2), units='inch')
    (x1, y1), (x2, y2) = layout.get_paper_limits()
    center_x = (x1+x2)/2
    center_y = (y1+y2)/2
    layout.add_line((x1, center_y), (x2, center_y))  # horizontal center line
    layout.add_line((center_x, y1), (center_x, y2))  # vertical center line
    layout.add_circle((0, 0), radius=.1)  # plot origin

if __name__ == '__main__':
    dwg = ezdxf.new('R12')
    draw_raster(dwg)
    setup_active_viewport(dwg)
    layout_page_setup(dwg)
    dwg.saveas(FILENAME)
    print("drawing '%s' created.\n" % FILENAME)


from future.utils import iteritems

import difflib

from recipe_engine.post_process import DropExpectation

DEPS = ['cipd', 'json', 'path', 'properties', 'step', 'swarming', 'buildbucket']

EXECUTION_TIMEOUT_SECS = 3600

def RunSteps(api):
  api.swarming.ensure_client()

  # Create a new Swarming task request.
  request = (api.swarming.task_request().
      with_name('recipes-go').
      with_priority(100).
      with_service_account('account@example.iam.gserviceaccount.com').
      with_realm('chromium:ci').
      with_resultdb())

  ensure_file = api.cipd.EnsureFile()
  ensure_file.add_package('infra/git/${platform}', 'version:2.14.1.chromium10')

  # Configure the first slice.
  request = (request.with_slice(0, request[0].
        with_command(['recipes', 'run', '"example"']).
        with_relative_cwd('some/subdir').
        with_dimensions(pool='example.pool', os='Debian').
        with_cipd_ensure_file(ensure_file).
        with_env_vars(SOME_VARNAME='stuff', GOPATH='$HOME/go').
        with_env_prefixes(PATH=["path/to/bin/dir", "path/to/other/bin/dir"]).
        with_expiration_secs(3600).
        with_wait_for_capacity(True).
        with_io_timeout_secs(600).
        with_execution_timeout_secs(EXECUTION_TIMEOUT_SECS).
        with_idempotent(True).
        with_containment_type('AUTO').
        with_named_caches({'cache_name': 'cache/path'}),
      )
  )

  request = request.with_slice(
      0, request[0].with_cas_input_root(
          '24b2420bc49d8b8fdc1d011a163708927532b37dc9f91d7d8d6877e3a86559ca/73')
  )

  # Check a request with no tags and no user can make it to JSON and back.
  # These requests should be considered valid.
  req_no_tag_no_user_jsonish = request.to_jsonish()
  api.swarming.task_request_from_jsonish(req_no_tag_no_user_jsonish)

  # Add user and tags for coverage of those.
  request = request.with_user('defaultuser').with_tags(
      {'key': ['value1', 'value2']})

  # Append a slice that is a variation of the last one as a starting point.
  request = request.add_slice(request[-1].with_grace_period_secs(
      20).with_secret_bytes(b'shh, don\'t tell').with_outputs(
          ['my/output/file']))

  # There should be three task slices at this point.
  assert len(request) == 2

  # Assert from_josnish(x.to_jonish()) == x
  jsonish = request.to_jsonish()
  from_jsonish = api.swarming.task_request_from_jsonish(jsonish)
  back_to_jsonish = from_jsonish.to_jsonish()
  diff = list(difflib.unified_diff(
      api.json.dumps(jsonish, indent=2).splitlines(),
      api.json.dumps(back_to_jsonish, indent=2).splitlines()))
  assert not diff, ''.join(diff)

  # Dimensions, and environment variables and prefixes can be unset.
  slice = request[-1]
  assert slice.dimensions == {'pool': 'example.pool', 'os': 'Debian'}
  assert slice.env_vars == {'SOME_VARNAME': 'stuff', 'GOPATH': '$HOME/go'}
  assert (slice.env_prefixes ==
          {'PATH' : ["path/to/bin/dir", "path/to/other/bin/dir"]})

  slice = (slice.
    with_dimensions(os=None).
    with_env_vars(GOPATH=None).
    with_env_prefixes(PATH=None)
  )

  assert slice.dimensions == {'pool': 'example.pool'}
  assert slice.env_vars == {'SOME_VARNAME': 'stuff'}
  assert slice.env_prefixes == {}

  # Setting environment prefixes is additive.
  slice = slice.with_env_prefixes(PATH=['a']).with_env_prefixes(PATH=['b'])
  assert slice.env_prefixes == {'PATH': ['a', 'b']}

  # Trigger the task request.
  metadata = api.swarming.trigger('trigger 1 task', requests=[request])

  # From the request metadata, one can access the task's name, ID, and
  # associated UI link.
  assert len(metadata) == 1
  metadata[0].name
  metadata[0].id
  metadata[0].task_ui_link
  metadata[0].invocation

  # Retrieve TaskRequest.
  api.swarming.test_api.set_task_for_show_request(request)
  retrieved_task = api.swarming.show_request('show-request', metadata[0])
  diff = list(
      difflib.unified_diff(
          api.json.dumps(jsonish, indent=2).splitlines(),
          api.json.dumps(retrieved_task.to_jsonish(), indent=2).splitlines()))
  assert not diff, '\n'.join(diff)

  # Or retrieve by ID.
  _ = api.swarming.show_request('show-request via task id', metadata[0].id)

  # Collect the result of the task by metadata.
  output_dir = api.path.mkdtemp('swarming')
  results = api.swarming.collect('collect', metadata, output_dir=output_dir,
                                 timeout='5m', verbose=True)
  # Or collect by ID.
  results += api.swarming.collect('collect other pending task', ['0'],
                                  eager=True)

  results[0].name
  results[0].id
  results[0].state
  results[0].success
  results[0].output
  results[0].outputs
  results[0].output_dir
  results[0].duration_secs
  results[0].bot_id
  results[0].raw

  # Raise an error if something went wrong.
  if not results[0].success:
    threw = False
    try:
      results[0].analyze()
    except api.step.StepFailure as e:
      threw = True
      s = str(e)
      if results[0].state == api.swarming.TaskState.BOT_DIED:
        assert s == 'The bot running this task died', repr(s)
      elif results[0].state == api.swarming.TaskState.CLIENT_ERROR:
        assert s == 'The task encountered an error caused by the client'
      elif results[0].state == api.swarming.TaskState.CANCELED:
        assert s == 'The task was canceled before it could run', repr(s)
      elif results[0].state == api.swarming.TaskState.COMPLETED:
        out = '(…)' + 'A' * 996
        assert s in ('Swarming task failed:\n' + out,
                     'Swarming task failed:\nNone'), repr(s)
      elif results[0].state == api.swarming.TaskState.EXPIRED:
        assert s == 'Timed out waiting for a bot to run on', repr(s)
      elif results[0].state == api.swarming.TaskState.KILLED:
        assert s == 'The task was killed mid-execution', repr(s)
      elif results[0].state == api.swarming.TaskState.NO_RESOURCE:
        assert s == 'Found no bots to run this task', repr(s)
      elif results[0].state == api.swarming.TaskState.TIMED_OUT:
        out = '(…)' + '\nDying' * 166
        expected = [
            'Timed out after 3599 seconds.\nOutput:\n' + out,
            'Execution timeout: exceeded 3600 seconds.\nOutput:\nhello world!',
            'I/O timeout: exceeded 600 seconds.\nOutput:\nhello world!',
        ]
        assert s in expected, repr(s)
      elif results[0].state is None:
        assert (
            s == 'Failed to collect:\nBot could not be contacted'), repr(s)
      else:  # pragma: no cover
        raise AssertionError('unexpected state: %r\n%r' % (results[0].state, s))
    except Exception as e:  # pragma: no cover
      raise AssertionError('wrong exception raised: %r' % e)
    if not threw:  # pragma: no cover
      raise AssertionError('exception was not raised')
  else:
    results[0].analyze()

  with api.swarming.on_path():
    api.step('some step with swarming on path', [])

  # verify swarming server correctly reverts
  api.swarming.trigger(
      'trigger on original server', requests=[request], verbose=True)
  api.swarming.collect('collect on original server', ['0'])

def GenTests(api):
  # For coverage
  api.swarming.example_task_request_jsonish()

  yield api.test('basic')

  yield api.test(
      'resultdb',
      api.override_step_data(
          'trigger 1 task', api.swarming.trigger(['recipes-go'],
                                                 resultdb=True)))

  yield api.test(
      'no-resultdb',
      api.override_step_data(
          'trigger 1 task', api.swarming.trigger(['recipes-go'],
                                                 resultdb=False)))

  states = {state.name : api.swarming.TaskState[state.name]
            for state in api.swarming.TaskState if state not in [
              api.swarming.TaskState.INVALID,
              api.swarming.TaskState.PENDING,
              api.swarming.TaskState.RUNNING,
              api.swarming.TaskState.TIMED_OUT,
            ]}
  states['unreachable'] = None

  for name, value in iteritems(states):

    result = api.swarming.task_result(
        id='0', name='recipes-go', state=value, outputs=('out.tar'),
    )
    yield api.test(
        'collect_with_state_%s' % name,
        api.override_step_data('collect', api.swarming.collect([result])),
    )

  timeout_result = api.swarming.task_result(
      id='100', name='recipes-go', duration=EXECUTION_TIMEOUT_SECS - 1,
      state=api.swarming.TaskState.TIMED_OUT,
      output='Dying\n' * 500,
  )
  yield api.test(
      'collect_with_state_TIMED_OUT',
      api.override_step_data('collect', api.swarming.collect([timeout_result])),
  )

  io_timeout_result = api.swarming.task_result(
      id='0', name='recipes-go', duration=EXECUTION_TIMEOUT_SECS - 1,
      state=api.swarming.TaskState.TIMED_OUT,
  )
  yield api.test(
      'collect_with_state_TIMED_OUT_by_io',
      api.override_step_data(
          'collect', api.swarming.collect([io_timeout_result])),
  )

  execution_timeout_result = api.swarming.task_result(
      id='0',
      name='recipes-go',
      duration=EXECUTION_TIMEOUT_SECS + 1,
      state=api.swarming.TaskState.TIMED_OUT,
  )
  yield api.test(
      'collect_with_state_TIMED_OUT_by_execution',
      api.override_step_data(
          'collect', api.swarming.collect([execution_timeout_result])),
  )

  failed_result = api.swarming.task_result(
      id='0', name='recipes-go', state=api.swarming.TaskState.COMPLETED,
      failure=True, outputs=('out.tar'),
      output='AAA'*500,
  )
  yield api.test(
      'collect_with_state_COMPLETED_and_failed',
      api.override_step_data('collect', api.swarming.collect([failed_result])),
  )

  no_output_result = api.swarming.task_result(
      id='0',
      name='recipes-go',
      state=api.swarming.TaskState.COMPLETED,
      failure=True,
      output=None,
  )
  yield api.test(
      'collect_with_no_output',
      api.override_step_data(
          'collect', api.swarming.collect([no_output_result])),
      api.post_process(DropExpectation),
  )

  yield api.test(
      'check_triggered_request',
      api.post_check(
          api.swarming.check_triggered_request,
          'trigger 1 task',
          lambda check, request: check(request[0].dimensions == {
            'os': 'Debian',
            'pool': 'example.pool'
          })),
      api.post_check(
          api.swarming.check_triggered_request,
          'trigger 1 task',
          lambda check, request: check(request[0].env_vars[
            'SOME_VARNAME'] == 'stuff'), lambda check, request: check(request[
              0].wait_for_capacity)),
      api.post_process(DropExpectation),
  )

  yield api.test(
      'show_request_invalid_key',
      api.override_step_data(
          'show-request',
          stdout=api.json.invalid(
              'swarming: failed to get task request. task ID = 0: failed to '
              'call TaskRequest: googleapi: Error 400: 0 is an invalid key.'),
          retcode=1),
      status='INFRA_FAILURE',
  )

  yield api.test('test_new_swarming_experiment',
                 api.buildbucket.ci_build(experiments=['swarming.prpc.cli']))


from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time

class CursoAutomacao:
    def __init__(self):
        chrome_options = Options()
        chrome_options.add_argument('--lang=pt-BR')
        self.driver = webdriver.Chrome(executable_path=r'./chromedriver.exe', options=chrome_options)

    def Iniciar(self):
        self.driver.get('http://www.waves.com.br')
        self.driver.maximize_window()
        self.pergunta = input("Qual praia vocês deseja verificar a previsão do mar? Joaquina, Mole, Campeche, Vila,Porto, Rosa Sul, Rosa Norte, Ribanceira ?")
        time.sleep(15)

        botao_wavescheck = self.driver.find_element_by_class_name("sf-with-ul")
        time.sleep(5)
        botao_wavescheck.click()

        botao_estado = self.driver.find_element_by_link_text("Santa Catarina")
        time.sleep(3)
        botao_estado.click()
        time.sleep(3)

        # print(f'{title} R$: {price}')

        botao_escolher_praia = self.driver.find_element_by_link_text(self.pergunta)
        time.sleep(3)
        botao_escolher_praia.click()
        time.sleep(2)
        self.driver.execute_script('window.scrollBy(0,800)')
        time.sleep(10)
        self.driver.execute_script('window.scrollBy(0,1200)')

curso = CursoAutomacao()
curso.Iniciar()


import bottlenose
import logging
import random
import time

from bs4 import BeautifulSoup

from dateutil import parser

from price_monitor import (
    app_settings,
    utils,
)

from urllib.error import HTTPError

logger = logging.getLogger('price_monitor.product_advertising_api')

class ProductAdvertisingAPI(object):
    """
    A wrapper class for the necessary Amazon Product Advertising API calls.
    See the API reference here: http://docs.aws.amazon.com/AWSECommerceService/latest/DG/CHAP_ApiReference.html
    See bottlenose here: https://github.com/lionheart/bottlenose
    """

    def __init__(self):
        self.__amazon = bottlenose.Amazon(
            AWSAccessKeyId=app_settings.PRICE_MONITOR_AWS_ACCESS_KEY_ID,
            AWSSecretAccessKey=app_settings.PRICE_MONITOR_AWS_SECRET_ACCESS_KEY,
            AssociateTag=app_settings.PRICE_MONITOR_AMAZON_PRODUCT_API_ASSOC_TAG,
            Region=app_settings.PRICE_MONITOR_AMAZON_PRODUCT_API_REGION,
            Parser=lambda response_text: BeautifulSoup(response_text, 'lxml'),
            ErrorHandler=ProductAdvertisingAPI.handle_error,
        )

    @staticmethod
    def __get_item_attribute(item, attribute):
        """
        Returns the attribute value from a bs4 parsed item.
        :param item: bs4 item returned from PA API upon item lookup
        :param attribute: the attribute to search for
        :return: the value if found, else None
        :rtype: basestring
        """
        value = item.itemattributes.find_all(attribute, recursive=False)
        return value[0].string if len(value) == 1 else None

    @staticmethod
    def format_datetime(value):
        """
        Formats the given value if it is not None in the given format.
        :param value: the value to format
        :type value: basestring
        :return: formatted datetime
        :rtype: basestring
        """
        if value is not None:
            try:
                return parser.parse(value)
            except ValueError:
                logger.error('Unable to parse %s to a datetime', value)
                return None

    @staticmethod
    def handle_error(error):
        """
        Generic error handler for bottlenose requests.
        @see https://github.com/lionheart/bottlenose#error-handling
        :param error: error information
        :type error: dict
        :return: if to retry the request
        :rtype: bool
        :
        """
        ex = error['exception']

        logger.error('Error upon requesting Amazon URL %s (Code: %s, Cache-URL: %s): %r', error['api_url'], error['cache_url'], ex, ex.code)

        # try reconnect
        if isinstance(ex, HTTPError) and ex.code == 503:
            time.sleep(random.expovariate(0.1))
            return True

        return False

    def lookup_at_amazon(self, item_ids):
        """
        Outsourced this call to better mock in tests.
        :param item_ids: the item ids
        :type item_ids: list
        :return: parsed xml
        :rtype: bs4.BeautifulSoup
        """
        return self.__amazon.ItemLookup(ItemId=','.join(item_ids), ResponseGroup=app_settings.PRICE_MONITOR_PA_RESPONSE_GROUP)

    def item_lookup(self, item_ids):
        """
        Lookup of the item with the given id on Amazon. Returns it values or None if something went wrong.
        :param item_ids: the item ids
        :type item_ids: list
        :return: the values of the item
        :rtype: dict
        """
        logger.info('starting lookup for ASINs %s', ', '.join(item_ids))
        item_response = self.lookup_at_amazon(item_ids)

        if getattr(item_response, 'items') is None:
            logger.error(
                'Request for item lookup (ResponseGroup: %s, ASINs: %s) returned nothing',
                app_settings.PRICE_MONITOR_PA_RESPONSE_GROUP,
                ', '.join(item_ids),
            )
            return dict()

        if item_response.items.request.isvalid.string == 'True':

            # the dict that will contain a key for every ASIN and as value the parsed values
            product_values = dict()

            for item_node in item_response.find_all(['item']):

                # parse the values
                try:
                    isbn = self.__get_item_attribute(item_node, 'isbn')
                    eisbn = self.__get_item_attribute(item_node, 'eisbn')
                    if eisbn is None and isbn is not None:
                        if len(isbn) == 13:
                            eisbn = isbn
                            isbn = None

                    item_values = {
                        'asin': item_node.asin.string,
                        'title': item_node.itemattributes.title.string,
                        'artist': item_node.itemattributes.artist.string if item_node.itemattributes.artist is not None else None,
                        'isbn': isbn,
                        'eisbn': eisbn,
                        'binding': item_node.itemattributes.binding.string,
                        'date_publication': self.format_datetime(self.__get_item_attribute(item_node, 'publicationdate')),
                        'date_release': self.format_datetime(self.__get_item_attribute(item_node, 'releasedate')),
                        'large_image_url': item_node.largeimage.url.string if item_node.largeimage.url is not None else None,
                        'medium_image_url': item_node.mediumimage.url.string if item_node.mediumimage.url is not None else None,
                        'small_image_url': item_node.smallimage.url.string if item_node.smallimage.url is not None else None,
                        'offer_url': utils.get_offer_url(item_node.asin.string),
                        'audience_rating': self.__get_item_attribute(item_node, 'audiencerating'),
                    }

                    # check if there are offers, if so add price
                    if item_node.offers is not None and int(item_node.offers.totaloffers.string) > 0:
                        item_values['price'] = float(int(item_node.offers.offer.offerlisting.price.amount.string) / 100)
                        item_values['currency'] = item_node.offers.offer.offerlisting.price.currencycode.string

                    # insert into main dict
                    product_values[item_values['asin']] = item_values
                except AttributeError:
                    raise
                    logger.error('fetching item values from returned XML for ASIN %s failed', item_node.asin)

            # check if all ASINs are included, if not write error message to log
            failed_asins = []
            for asin in item_ids:
                if asin not in product_values.keys():
                    failed_asins.append(asin)

            if failed_asins:
                logger.error('Lookup for the following ASINs failed: %s', ', '.join(failed_asins))

            # if there is at least a single ASIN in the list, return the list, else None
            return dict() if len(product_values) == 0 else product_values

        else:
            logger.error(
                'Request for item lookup (ResponseGroup: %s, ASINs: %s) was not valid',
                app_settings.PRICE_MONITOR_PA_RESPONSE_GROUP,
                ', '.join(item_ids),
            )
            return dict()


from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
import os

class Employee(Document):
	pass

@frappe.whitelist()
def create_permissions(name):
	supp_doc=frappe.get_doc("Supplier",name)
	users=frappe.db.get_list("User",filters={'represents_company':supp_doc.represents_company},fields={'*'})
	companies=frappe.db.get_list("Allowed To Transact With",filters={'parent':supp_doc.name,'parenttype':'Supplier'},fields={'*'})
	if users:
		if companies:
			for user in users:
				for company in companies:
					customers=frappe.db.get_all("Customer",filters={'represents_company':company.company},fields={'*'})
					for customer in customers:
						permission=frappe.db.get_list('User Permission',filters={'user':user.name,'allow':"Customer",'for_value':customer.name},fields={'*'})
						if not permission:
							up_doc=frappe.get_doc(dict(doctype = 'User Permission',
								user=user.name,
								allow="Customer",
								for_value=customer.name,
								apply_to_all_doctypes=1
							)).insert(ignore_mandatory=True)
							up_doc.save()
				permission=frappe.db.get_list('User Permission',filters={'user':user.name,'allow':"Supplier",'for_value':supp_doc.supplier_name},fields={'*'})
				if not permission:
							up_doc=frappe.get_doc(dict(doctype = 'User Permission',
								user=user.name,
								allow="Supplier",
								for_value=supp_doc.supplier_name,
								apply_to_all_doctypes=1
							)).insert(ignore_mandatory=True)
							up_doc.save()


try:
	import sys
	if sys.__name__ is None:
		raise ImportError("OMG! we could not import os. We're like in the matrix! ABORT. ABORT.")
except Exception as err:
	raise ImportError(err)

try:
	if 'os' not in sys.modules:
		import os
	else:  # pragma: no branch
		os = sys.modules["""os"""]
except Exception:
	raise ImportError("OS Failed to import.")

try:
	if 'argparse' not in sys.modules:
		import argparse
	else:  # pragma: no branch
		argparse = sys.modules["""argparse"""]
except Exception:
	raise ImportError("argparse Failed to import.")

try:
	if str("pku") in __file__:
		__sys_path__ = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
		if __sys_path__ not in sys.path:
			sys.path.insert(0, __sys_path__)
except Exception as importErr:
	print(str(importErr))
	print(str(importErr.args))
	importErr = None
	del importErr
	raise ImportError("Failed to import " + str(__file__))

try:
	if str("""piaplib""") not in sys.modules:
		raise ImportError("Pocket PKU failed to import.")  # import piaplib as piaplib
	piaplib = sys.modules["""piaplib"""]
except Exception:
	raise ImportError("Pocket PKU failed to import.")

try:
	if str("piaplib.pku.upgrade") not in sys.modules:
		from piaplib.pku import upgrade as upgrade
	else:
		upgrade = sys.modules[str("piaplib.pku.upgrade")]
except Exception:
	try:
		import piaplib.pku.upgrade as upgrade
	except Exception as err:
		raise ImportError(err, "Error Importing piaplib.pku.upgrade")

try:
	if str("piaplib.pku.config") not in sys.modules:
		from piaplib.pku import config as config
	else:
		config = sys.modules[str("piaplib.pku.config")]
except Exception:
	try:
		import piaplib.pku.config as config
	except Exception as err:
		raise ImportError(err, "Error Importing piaplib.pku.config")

try:
	if str("piaplib.pku.utils") not in sys.modules:
		from piaplib.pku import utils as utils
	else:
		utils = sys.modules[str("piaplib.pku.utils")]
	if utils.__name__ is None:
		raise ImportError("Error Importing piaplib.pku.utils")
except Exception:
	try:
		import piaplib.pku.utils as utils
	except Exception as err:
		raise ImportError(err, "Error Importing piaplib.pku.utils")

try:
	if str("piaplib.pku.remediation") not in sys.modules:
		from piaplib.pku import remediation as remediation
	else:
		remediation = sys.modules[str("piaplib.pku.remediation")]
except Exception:
	try:
		import piaplib.pku.remediation as remediation
	except Exception as err:
		raise ImportError(err, "Error Importing remediation")

try:
	if str("piaplib.pku.interfaces") not in sys.modules:
		from piaplib.pku import interfaces as interfaces
	else:
		interfaces = sys.modules[str("piaplib.pku.interfaces")]
except Exception:
	try:
		import piaplib.pku.interfaces as interfaces
	except Exception as err:
		raise ImportError(err, "Error Importing interfaces")

try:
	if str("piaplib.book.logs.logs") not in sys.modules:
		from piaplib.book.logs import logs as logs
	else:
		logs = sys.modules[str("piaplib.book.logs.logs")]
except Exception:
	try:
		import piaplib.book.logs.logs as logs
	except Exception as err:
		raise ImportError(err, "Error Importing piaplib.book.logs.logs")

__prog__ = """piaplib.pku"""
"""The name of this PiAPLib tool is Pocket Knife Unit"""

__description__ = """Pocket Knife Units. PiAP Pocket Controller for main tools."""
"""The description is 'Pocket Knife Unit PiAP Pocket Controller for main tools.'"""

__epilog__ = """Handles PiAP pockets tools"""
"""...Handles PiAP pockets tools"""

PKU_UNITS = {
	u'config': config,
	u'backup': None,
	u'upgrade': upgrade,
	u'help': None,
	u'interfaces': interfaces
}
""" The Pocket Knife Unit actions.
	config -  configuration stuff
	backup -  (FUTURE/RESERVED)
	upgrade -  (see reactive-firewall/PiAP-python-tools#1)
	help -  (FUTURE/RESERVED)
	"""

def generateParser(calling_parser_group):
	"""Parses the CLI arguments."""
	if calling_parser_group is None:
		parser = argparse.ArgumentParser(
			prog=__prog__,
			description=__description__,
			epilog=__epilog__
		)
	else:
		parser = calling_parser_group.add_parser(
			str(__prog__).split(".")[-1], help='the pocket pku service option.'
		)
	parser.add_argument('-V', '--version', action='version', version=str(
		"%(prog)s {}"
	).format(str(piaplib.__version__)))
	subparser = parser.add_subparsers(
		title="Units", dest='pku_unit',
		help='The pocket pku options.', metavar="PKU_UNIT"
	)
	for sub_parser in sorted(PKU_UNITS.keys()):
		if PKU_UNITS[sub_parser] is not None:
			subparser = PKU_UNITS[sub_parser].generateParser(subparser)
	if calling_parser_group is None:
		calling_parser_group = parser
	return calling_parser_group

@remediation.error_handling
def parseArgs(arguments=None):
	"""Parses the CLI arguments."""
	parser = generateParser(None)
	return parser.parse_known_args(arguments)

def usePKUTool(tool, arguments=[None]):
	"""Handler for launching pocket-tools."""
	theExitCode = 1
	if tool is None:
		theExitCode = 0
	elif tool in PKU_UNITS.keys():
		try:
			logs.log(str("pku launching: {}").format(str(tool)), "DEBUG")
			theExitCode = 0
			PKU_UNITS[tool].main(arguments)
		except Exception:
			logs.log(str("An error occurred while handling the PKU tool. "), "WARNING")
			logs.log(str("PKU failure."), "Error")
			theExitCode = 3
	return theExitCode

@remediation.bug_handling
def main(argv=None):
	"""The main event"""
	(args, extra) = parseArgs(argv)
	pku_cmd = args.pku_unit
	return usePKUTool(pku_cmd, argv[1:])

if __name__ in u'__main__':
	exit_code = main(sys.argv[1:])
	exit(exit_code)


#import pickle lib
import pickle

#creating a tuple to write to bin_file
computer = ('CPU RAM HARD DRIVE MOTHERBOARD',
            (('cpu', 'AMD Ryzen 9'), ('ram', 'Corsair 32gb'),
            ('hard drive', 'Samsung 1td ssd'), ('motherboard', 'ASUS ROG STRIX')))

computer_parts, computer_spec = computer

#using pickle.dump() to save computer tuple as a bin file
# with open("computer.bin", 'wb') as pickle_file:
#     #parameter   tuple    file variable
#     pickle.dump(computer, pickle_file)

####code above commented out as file as now been created so no need to create again############

#using pickle.load() to read computer.bin in readable format #parameters  file variable
with open("computer.bin", 'rb') as computer_pickled:
    computer = pickle.load(computer_pickled)

#print(computer)

#unpacking computer tuple that as now been read using pickle.load()
computer_description, computer_parts = computer

#printing out unpacked tuple
print(computer_description)

for parts in computer_parts:
    description, part = parts
    print(description, part)

print("-" * 30)

#variables created to add to computer.bin file
stock_left = [12, "Manchester", 10, "Sheffield", 2, "Newcastle"]

#using dump to now add stock_left list to computer.bin
#pickled.dump() parameters: item to be saved, file name, and protocol
with open("computer.bin", 'wb') as pickle_file:
    pickle.dump(computer, pickle_file)
    pickle.dump(stock_left, pickle_file)
    #we can also just add a variable here
    total_stock = stock_left[0] + stock_left[2] + stock_left[4]
    pickle.dump(total_stock, pickle_file)

#now reading computer.bin after dump of new items
#when reading items must be loaded in same order they where dump() into file
with open("computer.bin", 'rb') as computer_pickled:
    computer = pickle.load(computer_pickled)
    stock_and_area = pickle.load(computer_pickled)
    total_stock = pickle.load(computer_pickled)

#unpacking tuple
computer_description, computer_parts = computer

#printing out tuple
print(computer_description)

for parts in computer_parts:
    description, part = parts
    print(description, part)

#printing out new item stock_left that was added with dump() on line 46
print(stock_and_area)

#printing out new variable that was added on lines 48 and 49
print(total_stock)

#note protocols are not backwards compatible and there are safety concerns when loading pickled files
#from unknown source as this could have system commands with in