import logging

from pylons import config, request, response, session, tmpl_context as c
from pylons.controllers.util import abort, redirect
from pylons import url
from floof.lib.base import BaseController, render

log = logging.getLogger(__name__)

from floof.lib import file_storage as storage, helpers as h
from floof.model import Art, Rating, ArtUser
from floof.model.art import ArtUserType
from floof.model.comments import Discussion
from floof.model.users import User, UserRelationship

import elixir
#import magic
import os.path
import PIL
import PIL.Image
from sqlalchemy.exceptions import IntegrityError
from sqlalchemy.orm.exc import NoResultFound
from wtforms.validators import ValidationError
from wtforms import *


class ArtUploadForm(Form):
    by = TextField('Artists')
    by_me = BooleanField('me')
    file = FileField('Upload')
    url = TextField('Link')

    # TODO: make this general purpose
    def validate_file(self, field):
        if field.data == u'':
            raise ValidationError('File is required')
    

class ArtController(BaseController):
    def __before__(self, id=None):
        super(ArtController, self).__before__()
        # Awesome refactoring!
        if id:
            c.art = h.get_object_or_404(Art, id=id)

    def new(self):
        """ New Art! """
        c.form = ArtUploadForm()
        return render("/art/new.mako")

    # TODO: login required
    def create(self):
        c.form = ArtUploadForm(request.params)
        if not c.form.validate():
            ## TODO: JavaScript should be added to the upload form so that it is
            ## impossible to submit the form when it contains any invalid users, 
            ## so this never happens.  Only autocompled usernames should be allowed.
            return render("/art/new.mako")

        # Save the file
        upload = request.params['file']
        hash = storage.save_file('art/original', upload.file)

        # Create a thumbnail and a medium view
        img = PIL.Image.open(
            config['app_conf']['static_root']
            + storage.get_path('art/original', hash)[1:]
        )
        for subdir, config_size in [('medium',    config['medium_size']),
                                    ('thumbnail', config['thumbnail_size'])]:
            path = config['app_conf']['static_root'] + storage.get_path("art/{0}".format(subdir), hash)

            dir, _ = os.path.split(path)
            if not os.path.exists(dir):
                os.makedirs(dir)

            size = int(config_size)
            shrunken_img = img.copy()
            shrunken_img.thumbnail((size, size), PIL.Image.ANTIALIAS)
            shrunken_img.save(path, img.format)

        #magicker = magic.Magic(mime=True)
        buffer = upload.file.read(64)
        upload.file.seek(0)
        mimetype = 'image/unknown' #magickery.from_buffer(buffer)

        # XXX Ensure we can actually handle the mimetype

        print mimetype
        c.art = Art(
            uploader=c.user,
            original_filename=upload.filename,
            hash=hash,
            mimetype=mimetype,
        )
        c.art.discussion = Discussion(count=0)

        # <<<<<<< HEAD
        #         if c.form.by_me and c.user not in c.form.by.data:
        #             UserRelation(user=c.user, creator=c.user, kind="by", art=c.art)
        # 
        #         for artist in c.form.by.data:
        #             UserRelation(user=artist, creator=c.user, kind="by", art=c.art)
        # =======
        # For the moment, cheerfully assume that people are uploading their own
        # art
        ArtUser(art=c.art, user=c.user, type=ArtUserType.BY)
        # >>>>>>> origin/master


        try:
            elixir.session.commit()
            redirect(url('show_art', id=c.art.id))
        except IntegrityError:
            # XXX Check this as early as possible, and clean up the filesystem!
            # Right now this replaces the original file!
            hash = c.art.hash
            elixir.session.rollback()
            duplicate_art = Art.get_by(hash=hash)
            h.flash("We already have that one.")
            redirect(url('show_art', id=duplicate_art.id))



    def show(self, id):
        # c.art = h.get_object_or_404(Art, id=id)
        if c.user:
            c.your_score = c.art.user_score(c.user)
        return render("/art/show.mako")


    # TODO: login required
    def rate(self, id):
        # c.art = h.get_object_or_404(Art, id=id)
        score = request.params.get("score")
        if score and score.isnumeric():
            score = int(score)
        else:
            score = Rating.reverse_options.get(score)

        c.art.rate(score, c.user)
        elixir.session.commit()

        redirect(url('show_art', id=c.art.id))


    def watchstream(self, name):
        """Watchstream for a certain user."""
        try:
            c.watching_user = User.get_by(name=name)
        except NoResultFound:
            abort(404)

        # This user has watches which are users which have art
        # XXX use artist, not uploader
        c.artwork = Art.query.join(Art.uploader,
                                   User.target_of_relationships) \
                       .filter(UserRelationship.user_id == c.watching_user.id)

        return render('/index.mako')
