import time
import os, subprocess
import tempfile
import socket

from django_assets.filter import Filter


__all__ = ('LessFilter',)


class LessFilter(Filter):
    """Converts `Less <http://lesscss.org/>`_ markup to real CSS.

    If you want to combine it with other CSS filters, make sure this
    one runs first.

    **Note**: Currently, this needs to be the very first filter
    applied. Changes by filters that ran before will be lost.
    """
    """XXX: This currently needs to be the very first filter applied. This is
    because it uses the "source filter" mechanism to support "@includes"
    in less, i.e. it let's the less compiler work directly with the source
    file, and ignores the input stream. Filters previously already applied
    will be lost. Ways to solve this:
        - Let filters specify that they need to be first (and auto do so,
          or raise an exception).
        - Rewrite the less filter:
             - It could properly use the input stream, and just create the
               temp file in the same directory as the input path.
             - It could rewrite @includes via regex, as the cssrewrite filter
               does, before passing the tempfile on to lessc.

    XXX: Depending on how less is actually used in practice, it might actually
    be a valid use case to NOT have this be a source filter, so that one can
    split the css files into various less files, referencing variables in other
    files' - without using @include, instead having them merged together by
    django-assets. This will currently not work because we compile each
    file separately, and the compiler would fail at undefined variables.
    """

    name = 'less'
    is_source_filter = True

    def __init__(self):
        self.less = self.get_config('LESS_PATH', what='less binary')

    def apply(self, _in, out, source_path, output_path):
        """Less currently doesn't take data from stdin, and doesn't allow
        us from stdout either. Neither does it return a proper non-0 error
        code when an error occurs, or even write to stderr (stdout instead)!

        Hopefully this will improve in the future:

        http://groups.google.com/group/lesscss/browse_thread/thread/3aed033a44c51b4c/b713148afde87e81
        """
        # Use for debugging
        LESS_DAEMON = self.get_config('ASSETS_LESS_DAEMON', env=False, require=False)
        if LESS_DAEMON:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect(LESS_DAEMON)
            file = s.makefile('rw')
            try:
                file.write('%s\n' % source_path)
                file.flush()
                out.write(file.read())
            finally:
                s.close()
        else:
            outtemp_name = os.path.join(tempfile.gettempdir(),
                                        'assets_temp_%d.css' % int(time.time()))

            proc = subprocess.Popen([self.less, source_path, outtemp_name],
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE,
                                    # shell: necessary on windows to execute
                                    # ruby files, but doesn't work on linux.
                                    shell=(os.name == 'nt'))
            stdout, stderr = proc.communicate()

            # less only writes to stdout, as noted in the method doc, but
            # check everything anyway.
            if stdout or stderr or proc.returncode != 0:
                if os.path.exists(outtemp_name):
                    os.unlink(outtemp_name)
                raise Exception(('less: subprocess had error: stderr=%s, '+
                                'stdout=%s, returncode=%s') % (
                                                stderr, stdout, proc.returncode))

            outtemp = open(outtemp_name)
            try:
                out.write(outtemp.read())
            finally:
                outtemp.close()

                os.unlink(outtemp_name)
@@ -46,22 +46,8 @@
 file
-%0Aimport socket
 %0A%0Afr
@@ -2256,482 +2256,8 @@
 %22%22%22%0A
-        # Use for debugging%0A        LESS_DAEMON = self.get_config('ASSETS_LESS_DAEMON', env=False, require=False)%0A        if LESS_DAEMON:%0A            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)%0A            s.connect(LESS_DAEMON)%0A            file = s.makefile('rw')%0A            try:%0A                file.write('%25s%5Cn' %25 source_path)%0A                file.flush()%0A                out.write(file.read())%0A            finally:%0A                s.close()%0A        else:%0A    
     
@@ -2347,20 +2347,16 @@
         
- 
-   
 'assets_
@@ -2385,28 +2385,24 @@
 e.time()))%0A%0A
-    
         proc
@@ -2489,28 +2489,24 @@
             
-  
-  
 stdout=subpr
@@ -2509,36 +2509,32 @@
 ubprocess.PIPE,%0A
-    
                 
@@ -2605,20 +2605,16 @@
         
-  
-  
 # shell:
@@ -2646,20 +2646,16 @@
 execute%0A
-    
         
@@ -2751,20 +2751,16 @@
         
-   
- 
 shell=(o
@@ -2776,20 +2776,16 @@
  'nt'))%0A
-    
         
@@ -2817,28 +2817,24 @@
 municate()%0A%0A
-    
         # le
@@ -2899,20 +2899,16 @@
         
-    
 # check 
@@ -2926,20 +2926,16 @@
 anyway.%0A
-    
         
@@ -2991,20 +2991,16 @@
         
- 
-   
 if os.pa
@@ -3032,36 +3032,32 @@
                 
-    
 os.unlink(outtem
@@ -3076,20 +3076,16 @@
         
- 
-   
 raise Ex
@@ -3164,20 +3164,16 @@
         
-    
 'stdout=
@@ -3236,28 +3236,24 @@
             
-  
-  
 stderr, stdo
@@ -3279,28 +3279,24 @@
 ))%0A%0A        
-    
 outtemp = op
@@ -3324,21 +3324,13 @@
     
-   
- 
 try:%0A
-    
     
@@ -3363,20 +3363,16 @@
 read())%0A
-    
         
@@ -3388,28 +3388,24 @@
             
-    
 outtemp.clos
@@ -3405,28 +3405,24 @@
 mp.close()%0A%0A
-    
             

Remove the support for less daemon mode (added in 545022f7). This was never a good idea to begin with, and won't be necessary anymore with the upcoming cache and watch support.