/*
 * Copyright 2002-2004 the original author or authors.
 * 
 * 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.springframework.richclient.table.support;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.richclient.factory.LabelInfoFactory;
import org.springframework.util.Assert;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.swing.EventTableModel;
import ca.odell.glazedlists.swing.TableFormat;
import ca.odell.glazedlists.swing.WritableTableFormat;

/**
 * <code>TableModel</code> that accepts a <code>EventList</code>.
 * 
 * @author Peter De Bruycker
 */
public abstract class GlazedTableModel extends EventTableModel {

    private static final EventList EMPTY = new BasicEventList();

    private BeanWrapper beanWrapper = new BeanWrapperImpl();

    private String columnLabels[];

    private MessageSourceAccessor messages;

    private String propertyColumnNames[];

    public GlazedTableModel() {
        this((MessageSource) null);
    }

    public GlazedTableModel(Class beanClass, EventList rows) {
        this(rows, null);
    }

    public GlazedTableModel(EventList rows, MessageSource messageSource) {
        super(rows, null);
        setMessageSource(messageSource);
        setTableFormat(createTableFormat());
    }

    public GlazedTableModel(MessageSource messageSource) {
        this(EMPTY, messageSource);
    }

    public void setMessageSource(MessageSource messages) {
        if (messages != null) {
            this.messages = new MessageSourceAccessor(messages);
        } else {
            this.messages = null;
        }
    }

    protected abstract String[] createColumnPropertyNames();

    protected Object getColumnValue(Object row, int column) {
        beanWrapper.setWrappedInstance(row);
        return beanWrapper.getPropertyValue(propertyColumnNames[column]);
    }

    /**
     * May be overridden to achieve control over editable columns.
     * 
     * @param row
     *            the current row
     * @param column
     *            the column
     * @return editable
     */
    protected boolean isEditable(Object row, int column) {
        beanWrapper.setWrappedInstance(row);

        return beanWrapper.isWritableProperty(propertyColumnNames[column]);
    }

    protected Object setColumnValue(Object row, Object value, int column) {
        beanWrapper.setWrappedInstance(row);
        beanWrapper.setPropertyValue(propertyColumnNames[column], value);

        return row;
    }

    private String[] createColumnNames(String[] propertyColumnNames) {
        String[] columnNames = new String[propertyColumnNames.length];
        Assert.notNull(this.messages);
        for (int i = 0; i < propertyColumnNames.length; i++) {
            String columnPropertyName = propertyColumnNames[i];

            final String[] keys = { "label." + columnPropertyName, columnPropertyName };

            MessageSourceResolvable resolvable = new MessageSourceResolvable() {

                public String[] getCodes() {
                    return keys;
                }

                public Object[] getArguments() {
                    return null;
                }

                public String getDefaultMessage() {
                    if (keys.length > 0) {
                        return keys[0];
                    }
                    return "";
                }
            };

            columnNames[i] = LabelInfoFactory.createLabelInfo(messages.getMessage(resolvable)).getText();
        }

        return columnNames;
    }

    private TableFormat createTableFormat() {
        propertyColumnNames = createColumnPropertyNames();
        columnLabels = createColumnNames(propertyColumnNames);
        return new WritableTableFormat() {

            public int getColumnCount() {
                return columnLabels.length;
            }

            public String getColumnName(int column) {
                return columnLabels[column];
            }

            public Object getColumnValue(Object row, int column) {
                return GlazedTableModel.this.getColumnValue(row, column);
            }

            public boolean isEditable(Object row, int column) {
                return GlazedTableModel.this.isEditable(row, column);
            }

            public Object setColumnValue(Object row, Object value, int column) {
                return GlazedTableModel.this.setColumnValue(row, value, column);
            }
        };
    }
}
@@ -1494,16 +1494,21 @@
 st EMPTY
+_LIST
  = new B
@@ -1687,30 +1687,30 @@
  String 
-p
+columnP
 roperty
-Column
 Names%5B%5D;
@@ -1739,16 +1739,44 @@
 leModel(
+String%5B%5D columnPropertyNames
 ) %7B%0A    
@@ -1800,24 +1800,45 @@
 Source) null
+, columnPropertyNames
 );%0A    %7D%0A%0A  
@@ -1894,16 +1894,46 @@
 ist rows
+, String%5B%5D columnPropertyNames
 ) %7B%0A    
@@ -1947,24 +1947,45 @@
 s(rows, null
+, columnPropertyNames
 );%0A    %7D%0A%0A  
@@ -2045,32 +2045,62 @@
 ce messageSource
+, String%5B%5D columnPropertyNames
 ) %7B%0A        supe
@@ -2114,16 +2114,167 @@
  null);%0A
+        Assert.notEmpty(columnPropertyNames, %22ColumnPropertyNames parameter cannot be null.%22);%0A        this.columnPropertyNames = columnPropertyNames;%0A
         
@@ -2413,16 +2413,46 @@
 geSource
+, String%5B%5D columnPropertyNames
 ) %7B%0A    
@@ -2465,16 +2465,21 @@
 is(EMPTY
+_LIST
 , messag
@@ -2481,24 +2481,45 @@
 essageSource
+, columnPropertyNames
 );%0A    %7D%0A%0A  
@@ -2744,70 +2744,8 @@
  %7D%0A%0A
-    protected abstract String%5B%5D createColumnPropertyNames();%0A%0A
     
@@ -2887,38 +2887,38 @@
 opertyValue(
-p
+columnP
 roperty
-Column
 Names%5Bcolumn
@@ -3296,30 +3296,30 @@
 roperty(
-p
+columnP
 roperty
-Column
 Names%5Bco
@@ -3491,30 +3491,30 @@
 tyValue(
-p
+columnP
 roperty
-Column
 Names%5Bco
@@ -4667,114 +4667,55 @@
     
-propertyColumnNames = createColumnPropertyNames();%0A        columnLabels = createColumnNames(p
+columnLabels = createColumnNames(columnP
 roperty
-Column
 Name

fix for rcp-91: Allow specification of columnNames in constructor of GlazedTableModel