package com.partlyhuman.display
{
    import flash.geom.*;
    import flash.display.*;
    import flash.text.*;
    
    /**
    * Wraps left-justified text around any DisplayObject to produce a right rag.
    * See more information on http://www.partlyhuman.com/blog/roger/dynamic-text-wrapping-in-actionscript-3
    *
    * Work licensed under Creative Commons Attribution 3.0 United States License.
    * <http://creativecommons.org/licenses/by/3.0/us/>
    *
    * @author Roger Braunstein
    */
    
    public class WrapTextUtility
    {
        private static const KILL_LIMIT:int = 100;
        private static const GUTTER:int = 2;
        private static const NEWLINE:String = "\r";
        private static const WHITESPACE:RegExp = /[\s\-\_]/;
        
        public function WrapTextUtility()
        {
        }
        
        public static function convertToText(tf:TextField):void
        {
            tf.condenseWhite = false;
            tf.text = tf.text.replace(/<br\s*\/>/ig, NEWLINE);
        }
        
        public static function wrapText(tf:TextField, edge:DisplayObject, paddingPx:int = 6, transparentBackground:Boolean = false, debugSurface:Graphics = null):void
        {
            if (debugSurface) debugSurface.clear();
            if (!tf.hitTestObject(edge)) return;
                        
            var edgeOffset:Point = edge.localToGlobal(new Point()).subtract(tf.localToGlobal(new Point()));
            var lineY:Number = GUTTER;
            var bitmapSlice:BitmapData = new BitmapData(edge.width, edge.height, true, 0x00000000);
            var i:int = 0;
            
            do
            {
                try
                {
                    var lineMetrics:TextLineMetrics = tf.getLineMetrics(i);
                } catch (err:RangeError) {
                    break;
                }
                
                var lineBaseline:Number = lineY + lineMetrics.ascent;
                
                bitmapSlice.fillRect(bitmapSlice.rect, 0x00000000);
                var clipRect:Rectangle = new Rectangle(0, lineY - edgeOffset.y, edge.width, lineMetrics.ascent + lineMetrics.descent);
                lineY += lineMetrics.height;

                if (clipRect.width <= 0 || clipRect.height <= 0) continue;
                if (clipRect.y >= edge.height || clipRect.y + clipRect.height <= 0) continue;
                
                if (debugSurface)
                {
                    debugSurface.lineStyle(1, 0x808080);
                    debugSurface.drawRect(edge.x + clipRect.x, edge.y + clipRect.y, clipRect.width, clipRect.height);
                }

                bitmapSlice.draw(edge, null, null, null, clipRect);
                
                
                var colorRect:Rectangle = bitmapSlice.getColorBoundsRect((transparentBackground? 0xFF000000 : 0xFFFFFFFF), 0x00000000, false);
                if (colorRect == null || colorRect.width <= 0 || colorRect.height <= 0) continue;

                if (debugSurface)
                {
                    debugSurface.lineStyle(1, 0x00FF00);
                    debugSurface.drawRect(edge.x + colorRect.x, edge.y + colorRect.y, colorRect.width, colorRect.height);

                    debugSurface.lineStyle(1, 0xFF0000);
                    debugSurface.moveTo(tf.x, tf.y + lineBaseline);
                    debugSurface.lineTo(tf.x + colorRect.x + edgeOffset.x - paddingPx, tf.y + lineBaseline);
                }
                
                var wrapChar:int = tf.getCharIndexAtPoint(colorRect.x + edgeOffset.x - paddingPx, lineBaseline);
                var firstCharInLine:int = tf.getLineOffset(i);
                var allText:String = tf.text;
                
                if (wrapChar <= 0) continue;

                while (allText.charAt(wrapChar).match(WHITESPACE) == null && wrapChar > firstCharInLine)
                {
                    --wrapChar;
                }
                
                if (wrapChar <= firstCharInLine)
                {
                    tf.text = allText.slice(0, firstCharInLine) + NEWLINE + allText.slice(firstCharInLine);
                } else {
                    tf.text = allText.slice(0, wrapChar) + NEWLINE + allText.slice(wrapChar + 1);
                }
                
            } while (++i < KILL_LIMIT);
            
            bitmapSlice.dispose();
        }
    }
}