/*
* file: ResourceModel.java
* author: Scott Melville
* Jon Iles
* copyright: (c) Packwood Software 2002-2003
* date: 15/08/2002
*/
/*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
package net.sf.mpxj.mpx;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import net.sf.mpxj.MPXJException;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.Resource;
/**
* This class represents the resource table definition record in an MPX file.
* This record defines which fields are present in a resource record.
* This record has two forms, one textual and one numeric. Both
* variants are handled by this class.
*/
final class ResourceModel
{
/**
* Default constructor.
*
* @param file the parent file to which this record belongs.
* @param locale target locale
*/
ResourceModel(ProjectFile file, Locale locale)
{
m_parentFile = file;
setLocale(locale);
}
/**
* This method is used to update the locale specific data used by this class.
*
* @param locale target locale
*/
void setLocale(Locale locale)
{
m_resourceNames = LocaleData.getStringArray(locale, LocaleData.RESOURCE_NAMES);
String name;
m_resourceNumbers.clear();
for (int loop = 0; loop < m_resourceNames.length; loop++)
{
name = m_resourceNames[loop];
if (name != null)
{
m_resourceNumbers.put(name, Integer.valueOf(loop));
}
}
}
/**
* This method populates the resource model from data read from an MPX file.
*
* @param record data read from an MPX file
* @param isText flag indicating whether the tetxual or numeric data is being supplied
*/
public void update(Record record, boolean isText) throws MPXJException
{
int length = record.getLength();
for (int i = 0; i < length; i++)
{
if (isText == true)
{
add(getResourceCode(record.getString(i)));
}
else
{
add(record.getInteger(i).intValue());
}
}
}
/**
* This method is used to retrieve an array of field identifiers
* indicating the fields present in a resource record. Note that
* the values in this array will be terminated by -1.
*
* @return list of field names
*/
public int[] getModel()
{
m_fields[m_count] = -1;
return (m_fields);
}
/**
* This method is called to populate the arrays which are then
* used to generate the text version of the model.
*/
private void populateModel()
{
if (m_count != 0)
{
m_count = 0;
Arrays.fill(m_flags, false);
}
for (Resource resource : m_parentFile.getAllResources())
{
for (int loop = 0; loop < MPXResourceField.MAX_FIELDS; loop++)
{
if (resource.getCachedValue(MPXResourceField.getMpxjField(loop)) != null)
{
if (m_flags[loop] == false)
{
m_flags[loop] = true;
m_fields[m_count] = loop;
++m_count;
}
}
}
}
//
// Ensure the the model fields always appear in the same order
//
Arrays.sort(m_fields);
System.arraycopy(m_fields, m_fields.length - m_count, m_fields, 0, m_count);
}
/**
* This method generates a string in MPX format representing the
* contents of this record. Both the textual and numeric record
* types are written by this method.
*
* @return string containing the data for this record in MPX format.
*/
@Override public String toString()
{
populateModel();
int number;
char delimiter = m_parentFile.getProjectProperties().getMpxDelimiter();
StringBuilder textual = new StringBuilder();
StringBuilder numeric = new StringBuilder();
textual.append(MPXConstants.RESOURCE_MODEL_TEXT_RECORD_NUMBER);
numeric.append(MPXConstants.RESOURCE_MODEL_NUMERIC_RECORD_NUMBER);
for (int loop = 0; loop < m_count; loop++)
{
number = m_fields[loop];
textual.append(delimiter);
numeric.append(delimiter);
textual.append(getResourceField(number));
numeric.append(number);
}
textual.append(MPXConstants.EOL);
numeric.append(MPXConstants.EOL);
textual.append(numeric.toString());
return (textual.toString());
}
/**
* This method is called from the Resource class each time an attribute
* is added, ensuring that all of the attributes present in each resource
* record are present in the resource model.
*
* @param field field identifier
*/
private void add(int field)
{
if (field < m_flags.length)
{
if (m_flags[field] == false)
{
m_flags[field] = true;
m_fields[m_count] = field;
++m_count;
}
}
}
/**
* Given a resource field number, this method returns the resource field name.
*
* @param key resource field number
* @return resource field name
*/
private String getResourceField(int key)
{
String result = null;
if (key > 0 && key < m_resourceNames.length)
{
result = m_resourceNames[key];
}
return (result);
}
/**
* Given a resource field name, this method returns the resource field number.
*
* @param field resource field name
* @return resource field number
*/
private int getResourceCode(String field) throws MPXJException
{
Integer result = m_resourceNumbers.get(field);
if (result == null)
{
throw new MPXJException(MPXJException.INVALID_RESOURCE_FIELD_NAME + " " + field);
}
return (result.intValue());
}
private ProjectFile m_parentFile;
/**
* Array of flags indicating whether each field has already been
* added to the model.
*/
private boolean[] m_flags = new boolean[MPXResourceField.MAX_FIELDS];
/**
* Array of field numbers in order of their appearance.
*/
private int[] m_fields = new int[MPXResourceField.MAX_FIELDS + 1];
/**
* Count of the number of fields present.
*/
private int m_count;
/**
* Array of resource column names, indexed by ID.
*/
private String[] m_resourceNames;
/**
* Map to store Resource field Numbers.
*/
private HashMap<String, Integer> m_resourceNumbers = new HashMap<String, Integer>();
}