//  Copyright 2008, 2009, 2010 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.apache.tapestry5.dom;

public abstract class AbstractMarkupModel implements MarkupModel
{
    private final boolean useApostropheForAttributes;

    protected AbstractMarkupModel(boolean useApostropheForAttributes)
    {
        this.useApostropheForAttributes = useApostropheForAttributes;
    }

    public char getAttributeQuote()
    {
        return useApostropheForAttributes ? '\'' : '"';
    }

    /**
     * Passes all characters but '&lt;', '&gt;' and '&amp;' through unchanged.
     */
    public String encode(String content)
    {
        int length = content.length();

        StringBuilder builder = null;

        for (int i = 0; i < length; i++)
        {
            char ch = content.charAt(i);

            switch (ch)
            {
                case '<':

                    if (builder == null)
                    {
                        builder = new StringBuilder(2 * length);

                        builder.append(content.substring(0, i));
                    }

                    builder.append("&lt;");
                    continue;

                case '>':

                    if (builder == null)
                    {
                        builder = new StringBuilder(2 * length);

                        builder.append(content.substring(0, i));
                    }

                    builder.append("&gt;");
                    continue;

                case '&':

                    if (builder == null)
                    {
                        builder = new StringBuilder(2 * length);

                        builder.append(content.substring(0, i));
                    }

                    builder.append("&amp;");
                    continue;

                default:

                    if (builder != null)
                        builder.append(ch);
            }
        }

        return builder == null ? content : builder.toString();
    }

    public void encodeQuoted(String content, StringBuilder builder)
    {
        assert content != null;
        int length = content.length();

        for (int i = 0; i < length; i++)
        {
            char ch = content.charAt(i);

            switch (ch)
            {
                case '<':

                    builder.append("&lt;");
                    continue;

                case '>':

                    builder.append("&gt;");
                    continue;

                case '&':

                    builder.append("&amp;");
                    continue;

                case '"':

                    if (!useApostropheForAttributes)
                    {
                        builder.append("&quot;");
                        continue;
                    }

                    builder.append(ch);
                    continue;

                case '\'':

                    if (useApostropheForAttributes)
                    {
                        //TAP5-714
                        builder.append("&#39;");
                        continue;
                    }


                    // Fall through

                default:

                    builder.append(ch);
            }
        }
    }
}

@@ -2692,33 +2692,72 @@
 th()
-;%0A%0A        for (int i = 0
+, tokenStart = 0, i = 0;%0A        String delimiter;%0A        for (
 ; i 
@@ -2908,38 +2908,34 @@
         
-builder.append(
+delimiter = 
 %22&lt;%22
-)
 ;%0A      
@@ -2944,32 +2944,29 @@
             
-continue
+break
 ;%0A%0A         
@@ -3003,38 +3003,34 @@
         
-builder.append(
+delimiter = 
 %22&gt;%22
-)
 ;%0A      
@@ -3039,32 +3039,29 @@
             
-continue
+break
 ;%0A%0A         
@@ -3098,39 +3098,35 @@
         
-builder.append(
+delimiter = 
 %22&amp;%22
-)
 ;%0A      
@@ -3135,32 +3135,29 @@
             
-continue
+break
 ;%0A%0A         
@@ -3277,31 +3277,28 @@
     
-builder.append(
+delimiter = 
 %22&quot;%22
 );%0A 
@@ -3293,17 +3293,16 @@
 %22&quot;%22
-)
 ;%0A      
@@ -3315,32 +3315,29 @@
             
-continue
+break
 ;%0A          
@@ -3353,48 +3353,8 @@
  %7D%0A%0A
-                    builder.append(ch);%0A
     
@@ -3545,31 +3545,27 @@
     
-builder.append(
+delimiter = 
 %22&#39;%22
-)
 ;%0A  
@@ -3590,19 +3590,97 @@
     
-continue;%0A 
+break;%0A                    %7D%0A%0A%0A                    continue;%0A%0A%0A                default:%0A%0A
     
@@ -3686,35 +3686,42 @@
                 
-%7D%0A%0A
+ continue;
 %0A               
@@ -3717,24 +3717,27 @@
         
+%7D%0A%0A
         
 // Fall 
@@ -3732,50 +3732,114 @@
     
-// Fall through%0A%0A                default:%0A
+    if (tokenStart != i)%0A            %7B%0A                builder.append(content.subSequence(tokenStart, i));
 %0A   
@@ -3835,32 +3835,39 @@
 t, i));%0A        
+    %7D%0A%0A
             buil
@@ -3869,37 +3869,45 @@
  builder.append(
-ch
+delimiter
 );%0A
+%0A
             %7D%0A  
@@ -3894,33 +3894,175 @@
 );%0A%0A            
-%7D
+tokenStart = i + 1;%0A        %7D%0A%0A        if (tokenStart != length)%0A        %7B%0A            builder.append(content.subSequence(tokenStart, length));
 %0A        %7D%0A    %7D

improve performance of org.apache.tapestry5.dom.AbstractMarkupModel.encodeQuoted(String, StringBuilder)