import turbogears           as tg
import cherrypy
import commands
import socket
import md5
import time
import random
import os

from turbogears             import identity, flash, validators
from datetime               import datetime
from whatwhat               import utils
from textile                import textile
from whatwhat.widgets       import widgets

from whatwhat.model         import (Person, Project, Risk, Note, Question, 
                                    Answer, Issue, chance_codes, impact_codes,
                                    status_codes, ProjectFile)


class ProjectController(identity.SecureResource):
    require = identity.not_anonymous()
        
    @tg.expose()
    def default(self, *args, **kwargs):
        parts = cherrypy.request.path.rsplit('/')
        if len(parts) == 3 and parts[-1].isdigit():
            return self.project(parts[-1])
    
    
    @tg.expose()
    def index(self, *args, **kwargs):        
        project_id = self._active_project_id()
        if project_id:
            raise tg.redirect('/project/%s' % project_id)
        return self.locate()
    
    
    @tg.expose(template="whatwhat.templates.project.locate")
    def locate(self):
        all_projects = Project.select("parent_project_id is NULL order by upper(name)")
        projects = [project for project in all_projects if not project.archived]
        
        return dict(active_section='project',
                    projects=projects)
    
    
    @tg.expose(template="whatwhat.templates.project.project")
    @tg.validate(validators=dict(project_id=validators.Int()))
    def project(self, project_id):
        project = Project.get(project_id)
        user_person = Person.get(identity.current.user.id)
        groupids = utils.getGroups()
        
        cherrypy.response.simpleCookie['active_project_id'] = project_id
        cherrypy.response.simpleCookie['active_project_id']['path'] = '/'
        
        people = Person.select(orderBy='displayName')
        
        return dict(active_section='project',
                    project=project,
                    chance_codes=chance_codes, 
                    impact_codes=impact_codes,
                    status_codes=status_codes,
                    show_closed_risks=bool(self._show_closed_risks()),
                    show_closed_issues=bool(self._show_closed_issues()),
                    show_all_notes=bool(self._show_all_notes()),
                    people=people,
                    user_person=user_person,
                    groupids=groupids,
                    risks_widget=widgets.risks_widget,
                    issues_widget=widgets.issues_widget,
                    questions_widget=widgets.questions_widget,
                    notes_widget=widgets.notes_widget)
    
    
    @tg.expose()
    def toggle_closed_risks(self):
        if self._show_closed_risks():
            cherrypy.response.simpleCookie['show_closed_risks'] = 0
        else:
            cherrypy.response.simpleCookie['show_closed_risks'] = 1
        cherrypy.response.simpleCookie['show_closed_risks']['path'] = '/'
        
        raise tg.redirect('/project/%s' % self._active_project_id())
    
    
    @tg.expose()
    def toggle_closed_issues(self):
        if self._show_closed_issues():
            cherrypy.response.simpleCookie['show_closed_issues'] = 0
        else:
            cherrypy.response.simpleCookie['show_closed_issues'] = 1
        cherrypy.response.simpleCookie['show_closed_issues']['path'] = '/'
        
        raise tg.redirect('/project/%s' % self._active_project_id())
    
    
    @tg.expose()
    def toggle_show_all_notes(self):
        if self._show_all_notes():
            cherrypy.response.simpleCookie['show_all_notes'] = 0
        else:
            cherrypy.response.simpleCookie['show_all_notes'] = 1
        cherrypy.response.simpleCookie['show_all_notes']['path'] = '/'
        
        raise tg.redirect('/project/%s' % self._active_project_id())
    
    
    @tg.expose(fragment=True)
    @tg.validate(validators=dict(impact=validators.Int(), description=validators.String()))
    def create_issue(self, impact, description):
        creator = Person.get(identity.current.user.id)
        project = Project.get(self._active_project_id())
        
        issues = list(project.issues)
        
        issue = Issue(creator=creator, 
                      project=project, 
                      impact=impact,
                      issue=description)
        
        issues.append(issue)
        
        return widgets.issues_widget.render(issues=issues)
        
    
    @tg.expose(fragment=True)
    @tg.validate(validators=dict(impact=validators.Int(), chance=validators.Int(), description=validators.String()))
    def create_risk(self, impact, chance, description):
        creator = Person.get(identity.current.user.id)
        project = Project.get(self._active_project_id())
        
        risks = list(project.risks)
        
        risk = Risk(creator=creator, 
                    project=project, 
                    impact=impact, 
                    chance=chance, 
                    description=description)
        
        risks.append(risk)
        
        return widgets.risks_widget.render(risks=risks)
    
    
    @tg.expose(fragment=True)
    @tg.validate(validators=dict(question=validators.String()))
    def create_question(self, question):
        creator = Person.get(identity.current.user.id)
        project = Project.get(self._active_project_id())
        
        new_question = Question(creator=creator,
                                project=project,
                                question=question)
        
        return widgets.question_widget.render(question=new_question)
    
    
    @tg.expose(fragment=True)
    @tg.validate(validators=dict(question_id=validators.Int(), answer=validators.String()))
    def create_answer(self, question_id, answer):
        creator = Person.get(identity.current.user.id)
        question = Question.get(question_id)
        
        new_answer = Answer(creator=creator,
                            question=question,
                            answer=answer)
        
        return widgets.answer_widget.render(answer=new_answer)
    
    
    @tg.expose(fragment=True)
    @tg.validate(validators=dict(note=validators.String()))
    def create_note(self, note):
        creator = Person.get(identity.current.user.id)
        project = Project.get(self._active_project_id())
        
        note = Note(creator=creator, project=project, note=note)
        
        return widgets.note_widget.render(note=note, read_only=False)
    
    
    @tg.validate(validators=dict(note_id=validators.Int(), note=validators.String()))
    @tg.expose(fragment=True)
    def edit_note(self, note_id, note):
        n = Note.get(note_id)
        n.set(note=note, last_edit_date=datetime.now())
        
        return widgets.note_widget.render(note=n)
    
    
    @tg.expose()
    @tg.validate(validators=dict(note_id=validators.Int()))
    def remove_note(self, note_id):
        note = Note.get(note_id)
        Note.delete(note_id)
        return dict(success=True)
    
    
    @tg.expose(allow_json=True)
    @tg.validate(validators=dict(note_id=validators.Int()))
    def get_note_content(self, note_id, **kwargs):
        note = Note.get(note_id)
        cherrypy.response.headerMap['Pragma'] = 'no-cache'
        cherrypy.response.headerMap['Cache-Control'] ='no-cache'
        cherrypy.response.headerMap['Expires'] = -1
        
        return dict(note=note.note)
    
    
    @tg.expose(allow_json=True)
    @tg.validate(validators=dict(risk_id=validators.Int()))
    def close_risk(self, risk_id):
        risk = Risk.get(risk_id)
        risk.closed = True
        return dict(success=True)


    @tg.expose(allow_json=True)
    @tg.validate(validators=dict(issue_id=validators.Int()))
    def close_issue(self, issue_id):
        issue = Issue.get(issue_id)
        issue.closed = True
        return dict(success=True)


    @tg.expose(allow_json=True)
    @tg.validate(validators=dict(risk_id=validators.Int(), impact=validators.Int(), chance=validators.Int()))
    def modify_risk(self, risk_id, impact, chance):
        risk = Risk.get(risk_id)
        risk.set(impact=impact, chance=chance)
        return dict(success=True)
    
    
    @tg.expose(allow_json=True)
    @tg.validate(validators=dict(question_id=validators.Int()))
    def remove_question(self, question_id):
        question = Question.get(question_id)

        for answer in question.answers:
            answer.destroySelf()

        question.destroySelf()

        return dict(success=True)


    @tg.expose(allow_json=True)
    @tg.validate(validators=dict(answer_id=validators.Int()))
    def remove_answer(self, answer_id):
        answer = Answer.get(answer_id)
        answer.destroySelf()

        return dict(success=True)
        
    
    @tg.expose()
    def new_file(self, file):
        uploaddir = cherrypy.config.get('whatwhat.uploaddir')        
        try:
            if os.name == 'nt':
                filename = file.filename
                systemfilename = filename.split('.')[0] + self._uuid() + '.' + filename.split('.')[1]
                
            else:
                filename = file.filename
                systemfilename = filename.split('.')[0] + self._uuidgen() + '.' + filename.split('.')[1]
            f = open('%s%s' % (uploaddir, systemfilename), 'wb')
            while 1:
                data = file.file.read(1024*8)
                if not data:break
                f.write(data)
            f.close()
            
            creator = Person.get(cherrypy.request.identity.user.id)
            project = Project.get(self._active_project_id())
            
            ProjectFile(filename=filename, project=project, creator=creator, systemfilename=systemfilename)
        except:
            flash("Error creating file!")
        
        raise tg.redirect('/project/%s' % project.id)
        
    
    @tg.expose()
    @tg.validate(validators=dict(file_id=validators.Int()))
    def remove_file(self, file_id):
        uploaddir = cherrypy.config.get('whatwhat.uploaddir')
        file = ProjectFile.get(file_id)
        os.unlink('%s%s' % (uploaddir, file.systemfilename))
        ProjectFile.delete(file_id)
        
        raise tg.redirect('/project/%s' % file.project.id)
    
    
    @tg.expose(allow_json=True)    
    @tg.validate(validators=dict(contact_id=validators.Int(), status=validators.Int(), description=validators.String()))
    def update_project(self, contact_id, status, description):
        contact = Person.get(contact_id)
        project = Project.get(self._active_project_id())
        project.set(status=int(status), contact=contact, description=description)
        contact_content = '<a href="mailto:%s">%s</a>' % (contact.emailAddress, contact.displayName)
        desc = textile(description.encode('utf-8'), encoding='utf-8', output='ascii')
        return dict(success=True, description=desc, contact=contact_content)
    
        
    @tg.expose(allow_json=True)
    @tg.validate(validators=dict(issue_id=validators.Int(), impact=validators.Int()))
    def modify_issue(self, issue_id, impact):
        issue = Issue.get(issue_id)
        issue.impact = impact
        return dict(success=True)
    
    
    @tg.expose()
    def archive_project(self):
        project = Project.get(self._active_project_id())
        project.archived = True
        
        raise tg.redirect('/project/%s' % project.id)
    
    
    @tg.expose()
    def unarchive_project(self):
        project = Project.get(self._active_project_id())
        project.archived = False
        
        raise tg.redirect('/project/%s' % project.id)
        
    
    def _uuidgen(self):
        return commands.getoutput('uuidgen')
    
    
    def _uuid(self):
        t = long(time.time() * 1000)
        r = long(random.random() * 100000000000000000L)
        try:
            a = socket.gethostbyname(socket.gethostname())
        except:
            # if we can't get a network address, just imagine one
            a = random.random() * 100000000000000000L
        data = str(t)+' '+str(r)+' '+str(a)
        data = md5.md5(data).hexdigest()
        return data
    
    def _active_project_id(self):
        if cherrypy.request.simpleCookie.has_key('active_project_id'):
            return int(cherrypy.request.simpleCookie['active_project_id'].value)
        return None
    
    def _show_closed_issues(self):
        if cherrypy.request.simpleCookie.has_key('show_closed_issues'):
            return int(cherrypy.request.simpleCookie['show_closed_issues'].value)
        return 0
    
    def _show_closed_risks(self):
        if cherrypy.request.simpleCookie.has_key('show_closed_risks'):
            return int(cherrypy.request.simpleCookie['show_closed_risks'].value)
        return 0

    def _show_all_notes(self):
        if cherrypy.request.simpleCookie.has_key('show_all_notes'):
            return int(cherrypy.request.simpleCookie['show_all_notes'].value)
        return 0
