Are.java

// <editor-fold defaultstate="collapsed" desc="license">
/*
* Copyright (c) 2018, Karl H. Beckers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
*   this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
*   this list of conditions and the following disclaimer in the documentation
*   and/or other materials provided with the distribution.
* * Neither the name of the <ORGANIZATION> nor the names of its contributors
*   may be used to endorse or promote products derived from this software
*   without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
**/
// </editor-fold>
package net.jarre_de_the.griffin.file.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.jarre_de_the.griffin.Util;
import net.jarre_de_the.griffin.exception.NoFieldFoundException;
import net.jarre_de_the.griffin.file.Gff;
import net.jarre_de_the.griffin.types.data.ByteData;
import net.jarre_de_the.griffin.types.data.CExoLocStringData;
import net.jarre_de_the.griffin.types.data.CExoStringData;
import net.jarre_de_the.griffin.types.data.CResRefData;
import net.jarre_de_the.griffin.types.data.DWordData;
import net.jarre_de_the.griffin.types.data.IntData;
import net.jarre_de_the.griffin.types.data.ListData;
import net.jarre_de_the.griffin.types.data.StructData;
import net.jarre_de_the.griffin.types.data.WordData;
import net.jarre_de_the.griffin.types.field.AbstractField;
import net.jarre_de_the.griffin.types.field.AbstractField.FieldType;
import net.jarre_de_the.griffin.types.field.ByteField;
import net.jarre_de_the.griffin.types.field.CExoLocStringField;
import net.jarre_de_the.griffin.types.field.CExoStringField;
import net.jarre_de_the.griffin.types.field.CResRefField;
import net.jarre_de_the.griffin.types.field.DWordField;
import net.jarre_de_the.griffin.types.field.IntField;
import net.jarre_de_the.griffin.types.field.ListField;
import net.jarre_de_the.griffin.types.field.WordField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author charly4711
 */
public class Are extends Gff {

    public static final String DEFAULT_FILE_TYPE = "ARE ";
    public static final String DEFAULT_FILE_VERSION = "V3.2";
    private static final Logger LOGGER = LoggerFactory.getLogger(Are.class);

    public Are(File file) throws IOException {
        super(file);

        // make sure we have AreaTile objects in the list, so we can use the
        // convenience methods on them.
        ListField tileListField = (ListField) this.getField(AreField.TILE_LIST);
        if (null != tileListField && null != tileListField.getValue()) {
            ListData tileListData = tileListField.getValue();
            List<StructData> origList = tileListData.getValueAsList();
            if (null != origList && !origList.isEmpty()) {
                List<AreaTile> newList = new ArrayList<AreaTile>();

                for (int i = 0; i < origList.size(); i++) {
                    Are.AreaTile tile = new Are.AreaTile(origList.get(i).getId(),
                                                         origList.get(i).getValueAsList());
                    newList.add(tile);
                }
                ListData ld = new ListData(newList);
                tileListField.setData(ld);
            }
        }
    }

    @Override
    public Are clone() throws CloneNotSupportedException {
        Are clone = (Are) super.clone();
        return clone;
    }

    public enum AreField {
        ID("ID", FieldType.INT),
        CREATOR_ID("Creator_ID", FieldType.INT),
        VERSION("Version", FieldType.DWORD),
        TAG("Tag", FieldType.CExoString),
        NAME("Name", FieldType.CExoLocString),
        RESREF("ResRef", FieldType.CResRef),
        COMMENTS("Comments", FieldType.CExoString),
        //        //f: List(Expansion_List): net.jarre_de_the.griffin.types.data.ListData@0
        FLAGS("Flags", FieldType.DWORD),
        MOD_SPOT_CHECK("ModSpotCheck", FieldType.INT),
        MOD_LISTEN_CHECK("ModListenCheck", FieldType.INT),
        MOON_AMBIENT_COLOR("MoonAmbientColor", FieldType.DWORD),
        MOON_DIFFUSE_COLOR("MoonDiffuseColor", FieldType.DWORD),
        MOON_FOG_AMOUNT("MoonFogAmount", FieldType.BYTE),
        MOON_FOG_COLOR("MoonFogColor", FieldType.DWORD),
        MOON_SHADOWS("MoonShadows", FieldType.BYTE),
        SUN_AMBIENT_COLOR("SunAmbientColor", FieldType.DWORD),
        SUN_DIFFUSE_COLOR("SunDiffuseColor", FieldType.DWORD),
        SUN_FOG_AMOUNT("SunFogAmount", FieldType.BYTE),
        SUN_FOG_COLOR("SunFogColor", FieldType.DWORD),
        SUN_SHADOWS("SunShadows", FieldType.BYTE),
        IS_NIGHT("IsNight", FieldType.BYTE),
        LIGHTING_SCHEME("LightingScheme", FieldType.BYTE),
        SHADOW_OPACITY("ShadowOpacity", FieldType.BYTE),
        DAY_NIGHT_CYCLE("DayNightCycle", FieldType.BYTE),
        CHANCE_RAIN("ChanceRain", FieldType.INT),
        CHANCE_SNOW("ChanceSnow", FieldType.INT),
        CHANCE_LIGHTNING("ChanceLightning", FieldType.INT),
        WIND_POWER("WindPower", FieldType.INT),
        LOAD_SCREEN_ID("LoadScreenID", FieldType.WORD),
        PVP("PlayerVsPlayer", FieldType.BYTE),
        NO_REST("NoRest", FieldType.BYTE),
        WIDTH("Width", FieldType.INT),
        HEIGHT("Height", FieldType.INT),
        ON_ENTER("OnEnter", FieldType.CResRef),
        ON_EXIT("OnExit", FieldType.CResRef),
        ON_HEARTBEAT("OnHeartbeat", FieldType.CResRef),
        ON_USER_DEFINED("OnUserDefined", FieldType.CResRef),
        TILESET("Tileset", FieldType.CResRef),
        TILE_LIST("Tile_List", FieldType.List);

        private final String label;
        private final FieldType fieldType;

        private AreField(String label, FieldType fieldType) {
            this.label = label;
            this.fieldType = fieldType;
        }

        public String getLabel() {
            return label;
        }

        public FieldType getFieldType() {
            return fieldType;
        }
    }

    private AbstractField
            getField(AreField field
            ) {
        AbstractField fieldFound;
        try {
            fieldFound = this.getRootStruct().findLocalField(
                    field.fieldType.getFieldClassOfType(),
                    Util.stringToLabelArray(field.label));
        } catch (NoFieldFoundException ex) {
            fieldFound = null;
        }
        return fieldFound;
    }

    private void addField(AbstractField field) {
        this.getRootStruct().getValueAsList().add(field);
    }

    private int getIntFieldValue(AreField field) {
        int result = 0;
        IntField f = (IntField) getField(field);
        if (null != f && null != f.getValue()) {
            result = f.getValue().getValueAsNumber();
        }
        return result;
    }

    private void setIntFieldValue(AreField field, int value) {
        IntField f = (IntField) getField(field);
        if (null != f) {
            f.setData(new IntData(value));
        } else {
            f = new IntField(Util.stringToLabelArray(field.label),
                             new IntData(value));
            addField(f);
        }
    }

    private String getCResRefFieldValue(AreField field) {
        String result = null;
        CResRefField f = (CResRefField) getField(field);
        if (null != f && null != f.getValue()) {
            result = f.getValue().toString();
            if (result.isEmpty()) {
                result = null;
            }
        }
        return result;
    }

    private void setCResRefFieldValue(AreField field, String value) {
        CResRefField f = (CResRefField) getField(field);
        if (null != f) {
            f.setData(new CResRefData(value.getBytes(Util.CHARSET_US_ASCII)));
        } else {
            f = new CResRefField(
                    Util.stringToLabelArray(field.label),
                    new CResRefData(value.getBytes(Util.CHARSET_US_ASCII)));
            addField(f);
        }
    }

    private long getDwordFieldValue(AreField field) {
        long result = 0;
        DWordField f = (DWordField) getField(field);
        if (null != f && null != f.getValue()) {
            result = f.getValue().getValueAsNumber();
        }
        return result;
    }

    private void setDwordFieldValue(AreField field, long value) {
        DWordField f = (DWordField) getField(field);
        if (null != f) {
            f.setData(new DWordData(value));
        } else {
            f = new DWordField(
                    Util.stringToLabelArray(field.label),
                    new DWordData(value));
            addField(f);
        }
    }

    private short getByteFieldValue(AreField field) {
        short result = 0;
        ByteField f = (ByteField) getField(field);
        if (null != f && null != f.getValue()) {
            result = f.getValue().getValueAsNumber();
        }
        return result;
    }

    private void setByteFieldValue(AreField field, short value) {
        ByteField f;
        f = (ByteField) getField(field);
        if (null != f) {
            f.setData(new ByteData(value));
        } else {
            f = new ByteField(
                    Util.stringToLabelArray(field.label),
                    new ByteData(value));
            addField(f);
        }
    }

    private int getWordFieldValue(AreField field) {
        int result = 0;
        WordField f = (WordField) getField(field);
        if (null != f && null != f.getValue()) {
            result = f.getValue().getValueAsNumber();
        }
        return result;
    }

    private void setWordFieldValue(AreField field, short value) {
        WordField f = (WordField) getField(field);
        if (null != f) {
            f.setData(new WordData(value));
        } else {
            f = new WordField(
                    Util.stringToLabelArray(field.label),
                    new WordData(value));
            addField(f);
        }
    }

    private String getCExoStringFieldValue(AreField field) {
        String result = null;
        CExoStringField f = (CExoStringField) getField(field);
        if (null != f && null != f.getValue()) {
            result = f.getValue().toString();
            if (result.isEmpty()) {
                result = null;
            }
        }
        return result;
    }

    private void setCExoStringFieldValue(AreField field, String value) {
        byte[] buf;
        if (null == value) {
            buf = new byte[0];
        } else {
            buf = value.getBytes(Util.CHARSET_US_ASCII);
        }

        CExoStringField f = (CExoStringField) getField(field);
        if (null != f) {
            f.setData(new CExoStringData(buf));
        } else {
            f = new CExoStringField(
                    Util.stringToLabelArray(field.label),
                    new CExoStringData(buf));
            addField(f);
        }
    }

    private boolean getBooleanFromByteField(AreField field) {
        return 0 != getByteFieldValue(field);
    }

    public int getId() {
        return getIntFieldValue(AreField.ID);
    }

    public void setId(int value) {
        setIntFieldValue(AreField.ID, value);
    }

    public int getCreatorId() {
        return getIntFieldValue(AreField.CREATOR_ID);
    }

    public void setCreatorId(int value) {
        setIntFieldValue(AreField.CREATOR_ID, value);
    }

    public long getVersion() {
        return getDwordFieldValue(AreField.VERSION);
    }

    public void setVersion(long value) {
        setDwordFieldValue(AreField.VERSION, value);
    }

    public String getTag() {
        return getCExoStringFieldValue(AreField.TAG);
    }

    public void setTag(String value) {
        setCExoStringFieldValue(AreField.TAG, value);
    }

    public CExoLocStringData getName() {
        CExoLocStringField field
                = ((CExoLocStringField) getField(AreField.NAME));
        if (null != field) {
            return field.getValue();
        } else {
            return null;
        }
    }

    public void setName(CExoLocStringData value) {
        CExoLocStringField f = (CExoLocStringField) getField(AreField.NAME);

        // we remove the current field either way
        if (null != f) {
            Iterator<AbstractField> iter = getRootStruct().getValueAsList().iterator();
            while (iter.hasNext()) {
                AbstractField field = iter.next();
                if (field.equals(f)) {
                    iter.remove();
                }
            }
        }

        // and add it back, if we were passed a non-null value
        if (null != value) {
            CExoLocStringField newField = new CExoLocStringField(
                    Util.stringToLabelArray(AreField.NAME.label), value);
            addField(newField);
        }
    }

    public String getResRef() {
        return getCResRefFieldValue(AreField.RESREF);
    }

    public void setResRef(String value) {
        setCResRefFieldValue(AreField.RESREF, value);
    }

    public String getComments() {
        return getCExoStringFieldValue(AreField.COMMENTS);
    }

    public void setComments(String value) {
        setCExoStringFieldValue(AreField.COMMENTS, value);
    }

    public int getModSpotCheck() {
        return getIntFieldValue(AreField.MOD_SPOT_CHECK);
    }

    public void setModSpotCheck(int value) {
        setIntFieldValue(AreField.MOD_SPOT_CHECK, value);
    }

    public int getModListenCheck() {
        return getIntFieldValue(AreField.MOD_LISTEN_CHECK);
    }

    public void setModListenCheck(int value) {
        setIntFieldValue(AreField.MOD_LISTEN_CHECK, value);
    }

    public long getMoonAmbientColor() {
        return getDwordFieldValue(AreField.MOON_AMBIENT_COLOR);
    }

    public void setMoonAmbientColor(long value) {
        setDwordFieldValue(AreField.MOON_AMBIENT_COLOR, value);
    }

    public long getMoonDiffuseColor() {
        return getDwordFieldValue(AreField.MOON_DIFFUSE_COLOR);
    }

    public void setMoonDiffuseColor(long value) {
        setDwordFieldValue(AreField.MOON_DIFFUSE_COLOR, value);
    }

    public short getMoonFogAmount() {
        return getByteFieldValue(AreField.MOON_FOG_AMOUNT);
    }

    public void setMoonFogAmount(short value) {
        setByteFieldValue(AreField.MOON_FOG_AMOUNT, value);
    }

    public long getMoonFogColor() {
        return getDwordFieldValue(AreField.MOON_FOG_COLOR);
    }

    public void setMoonFogColor(long value) {
        setDwordFieldValue(AreField.MOON_FOG_COLOR, value);
    }

    public short getMoonShadows() {
        return getByteFieldValue(AreField.MOON_SHADOWS);
    }

    public void setMoonShadows(short value) {
        setByteFieldValue(AreField.MOON_SHADOWS, value);
    }

    public long getSunAmbientColor() {
        return getDwordFieldValue(AreField.SUN_AMBIENT_COLOR);
    }

    public void setSunAmbientColor(long value) {
        setDwordFieldValue(AreField.SUN_AMBIENT_COLOR, value);
    }

    public long getSunDiffuseColor() {
        return getDwordFieldValue(AreField.SUN_DIFFUSE_COLOR);
    }

    public void setSunDiffuseColor(long value) {
        setDwordFieldValue(AreField.SUN_DIFFUSE_COLOR, value);
    }

    public short getSunFogAmount() {
        return getByteFieldValue(AreField.SUN_FOG_AMOUNT);
    }

    public void setSunFogAmount(short value) {
        setByteFieldValue(AreField.SUN_FOG_AMOUNT, value);
    }

    public long getSunFogColor() {
        return getDwordFieldValue(AreField.SUN_FOG_COLOR);
    }

    public void setSunFogColor(long value) {
        setDwordFieldValue(AreField.SUN_FOG_COLOR, value);
    }

    public short getSunShadows() {
        return getByteFieldValue(AreField.SUN_SHADOWS);
    }

    public void setSunShadows(short value) {
        setByteFieldValue(AreField.SUN_SHADOWS, value);
    }

    public boolean isNight() {
        return getBooleanFromByteField(AreField.IS_NIGHT);
    }

    public void setNight(boolean value) {
        if (value) {
            setByteFieldValue(AreField.IS_NIGHT, (short) 1);
        } else {
            setByteFieldValue(AreField.IS_NIGHT, (short) 0);
        }
    }

    public short getLightingScheme() {
        return getByteFieldValue(AreField.LIGHTING_SCHEME);
    }

    public void setLightingScheme(short value) {
        setByteFieldValue(AreField.LIGHTING_SCHEME, value);
    }

    public short getShadowOpacity() {
        return getByteFieldValue(AreField.SHADOW_OPACITY);
    }

    public void setShadowOpacity(short value) {
        setByteFieldValue(AreField.SHADOW_OPACITY, value);
    }

    public boolean isDayNightCycle() {
        return getBooleanFromByteField(AreField.DAY_NIGHT_CYCLE);
    }

    public void setDayNightCycle(boolean value) {
        if (value) {
            setByteFieldValue(AreField.DAY_NIGHT_CYCLE, (short) 1);
        } else {
            setByteFieldValue(AreField.DAY_NIGHT_CYCLE, (short) 0);
        }
    }

    public int getChanceRain() {
        return getIntFieldValue(AreField.CHANCE_RAIN);
    }

    public void setChanceRain(int value) {
        setIntFieldValue(AreField.CHANCE_RAIN, value);
    }

    public int getChanceSnow() {
        return getIntFieldValue(AreField.CHANCE_SNOW);
    }

    public void setChanceSnow(int value) {
        setIntFieldValue(AreField.CHANCE_SNOW, value);
    }

    public int getChanceLightning() {
        return getIntFieldValue(AreField.CHANCE_LIGHTNING);
    }

    public void setChanceLightning(int value) {
        setIntFieldValue(AreField.CHANCE_LIGHTNING, value);
    }

    public int getWindPower() {
        return getIntFieldValue(AreField.WIND_POWER);
    }

    public void setWindPower(int value) {
        setIntFieldValue(AreField.WIND_POWER, value);
    }

    public int getLoadScreenId() {
        return getWordFieldValue(AreField.LOAD_SCREEN_ID);
    }

    public void setLoadScreenId(short value) {
        setWordFieldValue(AreField.LOAD_SCREEN_ID, value);
    }

    public short getPVP() {
        return getByteFieldValue(AreField.PVP);
    }

    public void setPVP(short value) {
        setByteFieldValue(AreField.PVP, value);
    }

    public boolean isNoRest() {
        return getBooleanFromByteField(AreField.NO_REST);
    }

    public void setNoRest(boolean value) {
        if (value) {
            setByteFieldValue(AreField.NO_REST, (short) 1);
        } else {
            setByteFieldValue(AreField.NO_REST, (short) 0);
        }
    }

    public int getWidth() {
        return getIntFieldValue(AreField.WIDTH);
    }

    public void setWidth(int value) {
        setIntFieldValue(AreField.WIDTH, value);
    }

    public int getHeight() {
        return getIntFieldValue(AreField.HEIGHT);
    }

    public void setHeight(int value) {
        setIntFieldValue(AreField.HEIGHT, value);
    }

    public String getOnEnter() {
        return getCResRefFieldValue(AreField.ON_ENTER);
    }

    public void setOnEnter(String value) {
        setCResRefFieldValue(AreField.ON_ENTER, value);
    }

    public String getOnExit() {
        return getCResRefFieldValue(AreField.ON_EXIT);
    }

    public void setOnExit(String value) {
        setCResRefFieldValue(AreField.ON_EXIT, value);
    }

    public String getOnHeartbeat() {
        return getCResRefFieldValue(AreField.ON_HEARTBEAT);
    }

    public void setOnHeartbeat(String value) {
        setCResRefFieldValue(AreField.ON_HEARTBEAT, value);
    }

    public String getOnUserDefined() {
        return getCResRefFieldValue(AreField.ON_USER_DEFINED);
    }

    public void setOnUserDefined(String value) {
        setCResRefFieldValue(AreField.ON_USER_DEFINED, value);
    }

    public String getTileset() {
        return getCResRefFieldValue(AreField.TILESET);
    }

    public void setOnTileset(String value) {
        setCResRefFieldValue(AreField.TILESET, value);
    }

    public boolean isInterior() {
        long mask = Long.parseLong("1", 2);
        long flags = getDwordFieldValue(AreField.FLAGS);
        return ((flags & mask) > 0);
    }

    public void setInterior(boolean value) {
        long flags = getDwordFieldValue(AreField.FLAGS);

        if (value) {
            long mask = Long.parseLong("1", 2);
            setDwordFieldValue(AreField.FLAGS, (short) (flags | mask));
        } else {
            long mask = Long.parseLong(
                    "111111111111111111111111111111111111111111111111111111111111110", 2);
            setDwordFieldValue(AreField.FLAGS, (short) (flags & mask));
        }
    }

    public boolean isUnderground() {
        long mask = Long.parseLong("10", 2);
        long flags = getDwordFieldValue(AreField.FLAGS);
        return ((flags & mask) > 0);
    }

    public void setUnderground(boolean value) {
        long flags = getDwordFieldValue(AreField.FLAGS);

        if (value) {
            long mask = Long.parseLong("10", 2);
            setDwordFieldValue(AreField.FLAGS, (short) (flags | mask));
        } else {
            long mask = Long.parseLong(
                    "111111111111111111111111111111111111111111111111111111111111101", 2);
            setDwordFieldValue(AreField.FLAGS, (short) (flags & mask));
        }
    }

    public boolean isNatural() {
        long mask = Long.parseLong("100", 2);
        long flags = getDwordFieldValue(AreField.FLAGS);
        return ((flags & mask) > 0);
    }

    public void setNatural(boolean value) {
        long flags = getDwordFieldValue(AreField.FLAGS);

        if (value) {
            long mask = Long.parseLong("100", 2);
            setDwordFieldValue(AreField.FLAGS, (short) (flags | mask));
        } else {
            long mask = Long.parseLong(
                    "111111111111111111111111111111111111111111111111111111111111011", 2);
            setDwordFieldValue(AreField.FLAGS, (short) (flags & mask));
        }
    }

    public List<AreaTile> getTileList() {
        ListField listField = ((ListField) getField(AreField.TILE_LIST));

        if (null != listField && null != listField.getValue()) {
            return listField.getValue().getValueAsList();
        } else {
            return null;
        }
    }

// I kinda like the idea of denying direct access to the flags DWord
// let's see if we can enforce going through the boolean flags
//    public long getFlags() {
//        return getDwordFieldValue(AreField.FLAGS);
//    }
//
    public static class AreaTile extends StructData {

        public static final int DEFAULT_STRUCT_ID = 1;

        public AreaTile() {
            super(new DWordData(DEFAULT_STRUCT_ID), new ArrayList<AbstractField>());
        }

        public AreaTile(DWordData id,
                        List<AbstractField> fields) {
            super(id, fields);
        }

        public enum AreaTileField {
            ANIM_LOOP1("Tile_AnimLoop1", FieldType.INT),
            ANIM_LOOP2("Tile_AnimLoop2", FieldType.INT),
            ANIM_LOOP3("Tile_AnimLoop3", FieldType.INT),
            HEIGHT("Tile_Height", FieldType.INT),
            ID("Tile_ID", FieldType.INT),
            MAIN_LIGHT1("Tile_MainLight1", FieldType.BYTE),
            MAIN_LIGHT2("Tile_MainLight2", FieldType.BYTE),
            ORIENTATION("Tile_Orientation", FieldType.INT),
            SRC_LIGHT1("Tile_SrcLight1", FieldType.BYTE),
            SRC_LIGHT2("Tile_SrcLight2", FieldType.BYTE);

            private final String label;
            private final FieldType fieldType;

            private AreaTileField(String label, FieldType fieldType) {
                this.label = label;
                this.fieldType = fieldType;
            }

            public String getLabel() {
                return label;
            }

            public FieldType getFieldType() {
                return fieldType;
            }
        }

        private AbstractField
                getField(AreaTileField field
                ) {
            AbstractField result = null;
            List<FoundField<AbstractField>> found
                    = this.<AbstractField>findField(
                            (Class<AbstractField>) field.fieldType.getFieldClassOfType(),
                            Util.stringToLabelArray(field.label));

            if (null != found
                    && !found.isEmpty()) {
                result = found.get(0).getField();
            }
            return result;
        }

        private void setIntFieldValue(AreaTileField field, int value) {
            IntField f = (IntField) getField(field);
            if (null == f) {
                f = new IntField(Util.stringToLabelArray(field.label),
                                 new IntData(value));
                this.getValueAsList().add(f);
            } else {
                f.setData(new IntData(value));
            }
        }

        private void setByteFieldValue(AreaTileField field, short value) {
            ByteField f = (ByteField) getField(field);
            if (null == f) {
                f = new ByteField(Util.stringToLabelArray(field.label),
                                  new ByteData(value));
                this.getValueAsList().add(f);
            } else {
                f.setData(new ByteData(value));
            }
        }

        public boolean getAnimLoop1() {
            boolean result = false;
            IntField f = (IntField) getField(AreaTileField.ANIM_LOOP1);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber() > 0;
            }
            return result;
        }

        public void setAnimLoop1(boolean value) {
            if (value) {
                setIntFieldValue(AreaTileField.ANIM_LOOP1, 1);
            } else {
                setIntFieldValue(AreaTileField.ANIM_LOOP1, 0);
            }
        }

        public boolean getAnimLoop2() {
            boolean result = false;
            IntField f = (IntField) getField(AreaTileField.ANIM_LOOP2);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber() > 0;
            }
            return result;
        }

        public void setAnimLoop2(boolean value) {
            if (value) {
                setIntFieldValue(AreaTileField.ANIM_LOOP2, 1);
            } else {
                setIntFieldValue(AreaTileField.ANIM_LOOP2, 0);
            }
        }

        public boolean getAnimLoop3() {
            boolean result = false;
            IntField f = (IntField) getField(AreaTileField.ANIM_LOOP3);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber() > 0;
            }
            return result;
        }

        public void setAnimLoop3(boolean value) {
            if (value) {
                setIntFieldValue(AreaTileField.ANIM_LOOP3, 1);
            } else {
                setIntFieldValue(AreaTileField.ANIM_LOOP3, 0);
            }
        }

        public int getHeight() {
            int result = 0;
            IntField f = (IntField) getField(AreaTileField.HEIGHT);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber();
            }
            return result;
        }

        public void setHeight(int value) {
            setIntFieldValue(AreaTileField.HEIGHT, value);
        }

        public int getTileId() {
            int result = 0;
            IntField f = (IntField) getField(AreaTileField.ID);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber();
            }
            return result;
        }

        public void setTileId(int value) {
            setIntFieldValue(AreaTileField.ID, value);
        }

        public short getMainLight1() {
            short result = 0;
            ByteField f = (ByteField) getField(AreaTileField.MAIN_LIGHT1);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber();
            }
            return result;
        }

        public void setMainLight1(short value) {
            setByteFieldValue(AreaTileField.MAIN_LIGHT1, value);
        }

        public short getMainLight2() {
            short result = 0;
            ByteField f = (ByteField) getField(AreaTileField.MAIN_LIGHT2);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber();
            }
            return result;
        }

        public void setMainLight2(short value) {
            setByteFieldValue(AreaTileField.MAIN_LIGHT2, value);
        }

        public int getOrientation() {
            int result = 0;
            IntField f = (IntField) getField(AreaTileField.ORIENTATION);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber();
            }
            return result;
        }

        public void setOrientation(int value) {
            setIntFieldValue(AreaTileField.ORIENTATION, value);
        }

        public short getSourceLight1() {
            short result = 0;
            ByteField f = (ByteField) getField(AreaTileField.SRC_LIGHT1);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber();
            }
            return result;
        }

        public void setSourceLight1(short value) {
            setByteFieldValue(AreaTileField.SRC_LIGHT1, value);
        }

        public short getSourceLight2() {
            short result = 0;
            ByteField f = (ByteField) getField(AreaTileField.SRC_LIGHT2);
            if (null != f && null != f.getValue()) {
                result = f.getValue().getValueAsNumber();
            }
            return result;
        }

        public void setSourceLight2(short value) {
            setByteFieldValue(AreaTile.AreaTileField.SRC_LIGHT2, value);
        }
    }

}