// ========================================================================
// Copyright 2007 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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.mortbay.cometd.filter;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.mortbay.cometd.ClientImpl;
import org.mortbay.util.ajax.JSON;

import dojox.cometd.Channel;
import dojox.cometd.Client;
import dojox.cometd.DataFilter;

/** JSON DataFilter
 * This {@link DataFilter} walks an Object as if it was a call to {@link JSON#toString(Object)} and 
 * calls the protected methods 
 * {@link #filterString(String)},
 * {@link #filterNumber(Number)},
 * {@link #filterBoolean(Boolean)},
 * {@link #filterArray(Object, ClientImpl)} or
 * {@link #filterMap(Map, ClientImpl)} appropriate.
 * Derived filters may override one or more of these methods to provide filtering of specific types.
 * 
 * @author gregw
 *
 */
public class JSONDataFilter implements DataFilter
{
    public void init(Object init)
    {}
    
    public Object filter(Client from, Channel to, Object data) throws IllegalStateException
    {
        if (data==null)
            return null;
        
        if (data instanceof Map)
            return filterMap(from,to,(Map)data);
        if (data instanceof List)
            return filterArray(from,to,((List) data).toArray ());
        if (data instanceof Collection)
        	return filterArray(from,to,((Collection)data).toArray());
        if (data.getClass().isArray() )
            return filterArray(from,to,data);
        if (data instanceof Number)
            return filterNumber((Number)data);
        if (data instanceof Boolean)
            return filterBoolean((Boolean)data);
        if (data instanceof String)
            return filterString((String)data);
        if (data instanceof JSON.Literal)
            return filterJSON(from,to,(JSON.Literal)data);
        if (data instanceof JSON.Generator)
            return filterJSON(from,to,(JSON.Generator)data);
        return filterString(data.toString());
    }

    protected Object filterString(String string)
    {
        return string;
    }

    protected Object filterBoolean(Boolean bool)
    {
        return bool;
    }

    protected Object filterNumber(Number number)
    {
        return number;
    }

    protected Object filterArray(Client from, Channel to, Object array)
    {
       if (array==null)
            return null;
        
        int length = Array.getLength(array);
        
        for (int i=0;i<length;i++)
            Array.set(array,i,filter(from, to, Array.get(array,i)));
        
        return array;
    }

    protected Object filterMap(Client from, Channel to, Map object)
    {
        if (object==null)
            return null;
        
        Iterator iter = object.entrySet().iterator();
        while(iter.hasNext())
        {
            Map.Entry entry = (Map.Entry)iter.next();
            entry.setValue(filter(from, to, entry.getValue()));
        }

        return object;
    }

    protected Object filterJSON(Client from, Channel to, JSON.Generator json)
    {
        StringBuffer buffer = new StringBuffer();
        json.addJSON (buffer);
        Object data = JSON.parse (buffer.toString ());
        return filter(from,to,data);
    }

    protected Object filterJSON(Client from, Channel to, JSON.Literal json)
    {
        Object data = JSON.parse(json.toString());
        return filter(from,to,data);
    }

}
