# Assorted Django validators

import os, tempfile

from reportlab.lib.rltempfile import get_rl_tempdir

from django.core import validators


# XXX where should this function live?
def formatFileSize(sizeInBytes):
    KILOBYTE = 1024
    MEGABYTE = 1024*1024
    if sizeInBytes < 2*MEGABYTE:
        return "%d Kb" % divmod(sizeInBytes, KILOBYTE)[0]
    else:
        return "%d Mb" % divmod(sizeInBytes, MEGABYTE)[0]


def isValidPdfFile(field_data, all_data):
    from rlextra.pageCatcher import pageCatcher
    data = field_data['content']
    try:
        pageCatcher.storeFormsInMemory(data, all=True)
    except ValueError:
        raise validators.ValidationError('The submitted file does not seem to be a valid PDF file.')

def replaceFileExt(filename, newExt):
    """
    >>> replaceFileExt('foo.txt', 'jpeg')
    'foo.jpeg'
    >>> replaceFileExt('/a/b/foo.txt', 'jpeg')
    '/a/b/foo.jpeg'
    >>> replaceFileExt('foo', 'jpeg')
    'foo.jpeg'
    >>> replaceFileExt('foo.a.b', 'jpeg')
    'foo.a.jpeg'

    No magic:

    >>> replaceFileExt('foo.txt', '.jpeg')
    'foo..jpeg'

    """
    name, ext = os.path.splitext(filename)
    return name+'.'+newExt


class EpsConvertor:

    def __init__(self, outDir=None, outSize=None, outFilename=None):
        self._outDir = outDir
        self.outSize = outSize
        self._outFilename = outFilename
        self.jpegFilename = None
        self.pdfFilename = None
        self._used = False

    def convert(self, data):
        """Raises ValueError on problems."""
        from rlextra.utils.pdf2jpeg import epsConvert
        assert not self._used, "instance should only be used once"
        self._used = True
        outFilename = self._outFilename
        outDir = self._outDir
        wantOutput = True
        tempDir = get_rl_tempdir()
        if outFilename is None:
            wantOutput = False
            outDir = tempDir
            junk, outFilename = tempfile.mkstemp('', 'tmp', outDir)
        fd, filename = tempfile.mkstemp('', 'tmp', tempDir)
        f = os.fdopen(fd, 'wb')
        f.write(data)
        f.close()
        filenames = epsConvert(
            filename,
            size=self.outSize,
            outDir=outDir,
            device='jpeg',
            outfile=replaceFileExt(outFilename, 'jpg'),  # XXX the extension is ignored here...
            preserveAspectRatio=True,
            )
        self.jpegFilename = filenames[0]
        filenames = epsConvert(
            filename,
            size=self.outSize,
            outDir=outDir,
            device='pdf',
            outfile=replaceFileExt(outFilename, 'pdf'),
            preserveAspectRatio=True,
            )
        self.pdfFilename = filenames[0]


class EpsValidator:

    def validate(self, field_data, all_data):
        ec = EpsConvertor()
        data = field_data['content']
        try:
            ec.convert(data)
        except ValueError, exc:
            raise validators.ValidationError(
                "The submitted file does not seem to be a valid EPS file")


class ArtworkValidator:

    def validate(self, field_data, all_data):
        ac = ArtworkConvertor()
        data = field_data['content']
        try:
            ac.convert(data)
        except ValueError:
            raise validators.ValidationError(
                "The submitted file does not seem to be a valid PDF, EPS, or bitmap (e.g. GIF or JPEG) file.")

class ArtworkConvertor:

    """

    This actually does the conversion to JPEG and PDF as a side-effect of
    validation (though the JPEG is only generated if the uploaded file was not
    already a JPEG, and the PDF only if an EPS was uploaded).  To avoid
    converting twice, the results of that are exposed through these attributes:

    bitmapFilename
    pdfFilename


    pdfFilename is only non-None if the uploaded file was a PDF or an EPS.  
    Otherwise, there will only be a bitmap file (not necessarily a JPEG), whose
    filename is in .bitmapFilename .

    The original type of the uploaded file is available through the fileType
    attribute.
    """

    def __init__(self, outDir=None, outSize=None, outFilename=None):
        self._outDir = outDir
        self.outSize = outSize
        self._outFilename = outFilename
        if outFilename is None:
            assert outDir is None
        self.isVector = None
        self.bitmapFilename = None
        self.pdfFilename = None
        self.fileType = None
        self._used = False

    def convert(self, data):
        from rlextra.utils.pdf2jpeg import pdfConvert
        assert not self._used, "instance should only be used once"
        self._used = True
        outFilename = self._outFilename
        outDir = self._outDir
        wantOutput = True
        if outFilename is None:
            wantOutput = False
            outDir = get_rl_tempdir()
            junk, outFilename = tempfile.mkstemp('', 'tmp', outDir)
        # feed it to pageCatcher...
        try:
            isValidPdfFile({'content': data}, {})  # XXX hack
        except validators.ValidationError, pdfExc:
            # ...no, try PIL...
            try:
                validators.isValidImage({'content': data}, {})  # XXX hack
            except validators.ValidationError, bitmapExc:
                # no, try GhostScript
                ev = EpsConvertor(outDir, self.outSize, outFilename)
                try:
                    ev.convert(data)
                except ValueError, exc:
                    raise ValueError(
                        "The submitted file does not seem to be a valid PDF, EPS, or bitmap (e.g. GIF or JPEG) file."
                        )
                else:
                    self.fileType = 'eps'
                    self.isVector = True
                    self.pdfFilename = ev.pdfFilename
                    self.bitmapFilename = ev.jpegFilename
            else:
                self.fileType = 'jpg'  # XXXX wrong, ask PIL
                self.isVector = False
        else:
            if not wantOutput:
                # already have a temp dir
                tempDir = outDir
            else:
                tempDir = get_rl_tempdir()
            fd, filename = tempfile.mkstemp('', 'tmp', tempDir)
            f = os.fdopen(fd, 'wb')
            f.write(data)
            f.close()
            filenames = pdfConvert(
                filename,
                size=self.outSize,
                outDir=outDir,
                device='jpeg',
                preserveAspectRatio=True,
                outfile=replaceFileExt(outFilename, 'jpg'),
                boxName='art',
                pageNo=0,
                )
            self.fileType = 'pdf'
            self.isVector = True
            self.bitmapFilename = filenames[0]


if __name__ == '__main__':
    import doctest
    doctest.testmod()
