#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
#

#  Copyright (C) 2015  Rafael Senties Martinelli <rsm@imap.cc>
#
#  This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License 3 as published by
#   the Free Software Foundation.
#
#  This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software Foundation,
#   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.

"""
    ** This file contains "cssmin 0.2.0" - A Python port of the YUI CSS compressor. **
    
    This file is a css compressor/decompressor for BlueFish. If you put this file over:
        /usr/share/bluefish/cssmin.py
        
    The cssmin option of bluefish will compress uncompressed code, and decompress compressed code.
    
"""


__version__ = '1.3~0'


import sys


def inside_brackets(start, end, text):
	for i in range(start, end):
		if text[i]=='}':
			return True
		elif text[i]=='{':
			return False
			
	return False
	
def CSS_decompresser(text):
    
    for char in ['\t','\n']:
        text=text.replace(char,'')

    indent_level=0
    new_text=''
    text_lenght=len(text)
    for i in range(text_lenght):
        
        chars={k:'' for k in range(-4,3)}
        
        for k in range(-5,3):
            try:
                chars[k]=text[i+k]
            except:
				pass
        
        char=chars[0]
        
        if 	(char in [',','%','>'] and not chars[1] in [';',' ']) or \
				(char == 's' and chars[-1].isdigit() and not chars[1]+chars[2]=='ol') or \
				(char == ':' and not chars[1] == ' ' and inside_brackets(i, text_lenght, text)) or \
				(char in ['n','x'] and chars[-4].isdigit() and ''.join(chars[x] for x in range(-3,1)) in ['vmin','vmax']) or \
				(char == ['m'] and chars[-3].isdigit() and ''.join(chars[x] for x in range(-2,1)) == 'rem') or \
				(char == ')' and not chars[1] in [' ',';']) or \
				(char in ['m','x','n','t','c','h','v'] and not chars[-3]==' ' and chars[-2].isdigit() \
					and chars[-1]+char in ['em','ex','px','cm','mm','in','pt','pc','ch','vh','vw'] and chars[1] != ';'):
        
            char+=' '
        
        
        elif 	(char == '#' and chars[-1] == ':') or \
				(char == '.' and not chars[-1].isdigit() and chars[1].isdigit()):
					
            char = ' '+char
    
        elif char == '{':
            indent_level+=1
            char =' {\n'+'\t'*indent_level
            
        elif char == '}':
            indent_level-=1
            char ='\n'+'\t'*indent_level+'}'
            if chars[1] != '}':
                char+='\n'+'\t'*indent_level
            
            if indent_level==0:
                char+='\n'
            
        elif char == ';':
            char = ';\n'+'\t'*indent_level
            
        new_text+=char
        
    return new_text.replace('  ',' ')
    

"""




     C S S   M I N




""" 
    
try:
    from StringIO import StringIO # The pure-Python StringIO supports unicode.
except ImportError:
    from io import StringIO
import re

def remove_comments(css):
    """Remove all CSS comment blocks."""

    iemac = False
    preserve = False
    comment_start = css.find("/*")
    while comment_start >= 0:
        # Preserve comments that look like `/*!...*/`.
        # Slicing is used to make sure we don"t get an IndexError.
        preserve = css[comment_start + 2:comment_start + 3] == "!"

        comment_end = css.find("*/", comment_start + 2)
        if comment_end < 0:
            if not preserve:
                css = css[:comment_start]
                break
        elif comment_end >= (comment_start + 2):
            if css[comment_end - 1] == "\\":
                # This is an IE Mac-specific comment; leave this one and the
                # following one alone.
                comment_start = comment_end + 2
                iemac = True
            elif iemac:
                comment_start = comment_end + 2
                iemac = False
            elif not preserve:
                css = css[:comment_start] + css[comment_end + 2:]
            else:
                comment_start = comment_end + 2
        comment_start = css.find("/*", comment_start)

    return css


def remove_unnecessary_whitespace(css):
    """Remove unnecessary whitespace characters."""

    def pseudoclasscolon(css):

        """
        Prevents 'p :link' from becoming 'p:link'.

        Translates 'p :link' into 'p ___PSEUDOCLASSCOLON___link'; this is
        translated back again later.
        """

        regex = re.compile(r"(^|\})(([^\{\:])+\:)+([^\{]*\{)")
        match = regex.search(css)
        while match:
            css = ''.join([
                css[:match.start()],
                match.group().replace(":", "___PSEUDOCLASSCOLON___"),
                css[match.end():]])
            match = regex.search(css)
        return css

    css = pseudoclasscolon(css)
    # Remove spaces from before things.
    css = re.sub(r"\s+([!{};:>+\(\)\],])", r"\1", css)

    # If there is a `@charset`, then only allow one, and move to the beginning.
    css = re.sub(r"^(.*)(@charset \"[^\"]*\";)", r"\2\1", css)
    css = re.sub(r"^(\s*@charset [^;]+;\s*)+", r"\1", css)

    # Put the space back in for a few cases, such as `@media screen` and
    # `(-webkit-min-device-pixel-ratio:0)`.
    css = re.sub(r"\band\(", "and (", css)

    # Put the colons back.
    css = css.replace('___PSEUDOCLASSCOLON___', ':')

    # Remove spaces from after things.
    css = re.sub(r"([!{}:;>+\(\[,])\s+", r"\1", css)

    return css


def remove_unnecessary_semicolons(css):
    """Remove unnecessary semicolons."""

    return re.sub(r";+\}", "}", css)


def remove_empty_rules(css):
    """Remove empty rules."""

    return re.sub(r"[^\}\{]+\{\}", "", css)


def normalize_rgb_colors_to_hex(css):
    """Convert `rgb(51,102,153)` to `#336699`."""

    regex = re.compile(r"rgb\s*\(\s*([0-9,\s]+)\s*\)")
    match = regex.search(css)
    while match:
        colors = map(lambda s: s.strip(), match.group(1).split(","))
        hexcolor = '#%.2x%.2x%.2x' % tuple(map(int, colors))
        css = css.replace(match.group(), hexcolor)
        match = regex.search(css)
    return css


def condense_zero_units(css):
    """Replace `0(px, em, %, etc)` with `0`."""

    return re.sub(r"([\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", r"\1\2", css)


def condense_multidimensional_zeros(css):
    """Replace `:0 0 0 0;`, `:0 0 0;` etc. with `:0;`."""

    css = css.replace(":0 0 0 0;", ":0;")
    css = css.replace(":0 0 0;", ":0;")
    css = css.replace(":0 0;", ":0;")

    # Revert `background-position:0;` to the valid `background-position:0 0;`.
    css = css.replace("background-position:0;", "background-position:0 0;")

    return css


def condense_floating_points(css):
    """Replace `0.6` with `.6` where possible."""

    return re.sub(r"(:|\s)0+\.(\d+)", r"\1.\2", css)


def condense_hex_colors(css):
    """Shorten colors from #AABBCC to #ABC where possible."""

    regex = re.compile(r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])")
    match = regex.search(css)
    while match:
        first = match.group(3) + match.group(5) + match.group(7)
        second = match.group(4) + match.group(6) + match.group(8)
        if first.lower() == second.lower():
            css = css.replace(match.group(), match.group(1) + match.group(2) + '#' + first)
            match = regex.search(css, match.end() - 3)
        else:
            match = regex.search(css, match.end())
    return css


def condense_whitespace(css):
    """Condense multiple adjacent whitespace characters into one."""

    return re.sub(r"\s+", " ", css)


def condense_semicolons(css):
    """Condense multiple adjacent semicolon characters into one."""

    return re.sub(r";;+", ";", css)


def wrap_css_lines(css, line_length):
    """Wrap the lines of the given CSS to an approximate length."""

    lines = []
    line_start = 0
    for i, char in enumerate(css):
        # It's safe to break after `}` characters.
        if char == '}' and (i - line_start >= line_length):
            lines.append(css[line_start:i + 1])
            line_start = i + 1

    if line_start < len(css):
        lines.append(css[line_start:])
    return '\n'.join(lines)


def cssmin(css, wrap=None):
    css = remove_comments(css)
    css = condense_whitespace(css)
    # A pseudo class for the Box Model Hack
    # (see http://tantek.com/CSS/Examples/boxmodelhack.html)
    css = css.replace('"\\"}\\""', "___PSEUDOCLASSBMH___")
    css = remove_unnecessary_whitespace(css)
    css = remove_unnecessary_semicolons(css)
    css = condense_zero_units(css)
    css = condense_multidimensional_zeros(css)
    css = condense_floating_points(css)
    css = normalize_rgb_colors_to_hex(css)
    css = condense_hex_colors(css)
    if wrap is not None:
        css = wrap_css_lines(css, wrap)
    css = css.replace("___PSEUDOCLASSBMH___", '"\\"}\\""')
    css = condense_semicolons(css)
    return css.strip()


def main(input):
    import optparse

    p = optparse.OptionParser(
        prog="cssmin", version=__version__,
        usage="%prog [--wrap N]",
        description="""Reads raw CSS from stdin, and writes compressed CSS to stdout.""")

    p.add_option(
        '-w', '--wrap', type='int', default=None, metavar='N',
        help="Wrap output to approximately N chars per line.")

    options, args = p.parse_args()
    sys.stdout.write(cssmin(input, wrap=options.wrap))  
    
    
if __name__ == '__main__':
    
    input=sys.stdin.read()
    
    text=cssmin(input).strip()
    if input.strip() == text:
        text=CSS_decompresser(input)

    sys.stdout.write(text)
    
