/*
 * Copyright (C) 2006 Joe Walnes.
 * Copyright (C) 2007, 2008, 2009 XStream Committers.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 * 
 * Created on 13. June 2006 by Guilherme Silveira
 */
package com.thoughtworks.xstream.persistence;

import com.thoughtworks.xstream.XStream;

import java.io.File;


/**
 * PersistenceStrategy to assign string based keys to objects persisted in files. The file
 * naming strategy is based on the key's type name and its toString method. It escapes non
 * digit, non a-z and A-Z characters. In order to change the escaping/unescaping algorithm,
 * simply extend this class and rewrite its getName/extractKey methods. Note, this
 * implementation silently implies that the keys actually are Strings, since the keys will be
 * turned into string keys at deserialization time.
 * 
 * @author Guilherme Silveira
 * @deprecated As of 1.3.1, use FilePersistenceStrategy
 */
public class FileStreamStrategy extends AbstractFilePersistenceStrategy implements
    StreamStrategy {
    public FileStreamStrategy(final File baseDirectory) {
        this(baseDirectory, new XStream());
    }

    public FileStreamStrategy(final File baseDirectory, final XStream xstream) {
        super(baseDirectory, xstream, null);
    }

    /**
     * Given a filename, the unescape method returns the key which originated it.
     * 
     * @param name the filename
     * @return the original key
     */
    protected Object extractKey(final String name) {
        final String key = unescape(name.substring(0, name.length() - 4));
        return key.equals("\0") ? null : key;
    }

    protected String unescape(final String name) {
        final StringBuffer buffer = new StringBuffer();
        char lastC = '\uffff';
        int currentValue = -1;
        // do we have a regex master to do it?
        final char[] array = name.toCharArray();
        for (int i = 0; i < array.length; i++ ) {
            final char c = array[i];
            if (c == '_' && currentValue != -1) {
                if (lastC == '_') {
                    buffer.append('_');
                } else {
                    buffer.append((char)currentValue);
                }
                currentValue = -1;
            } else if (c == '_') {
                currentValue = 0;
            } else if (currentValue != -1) {
                currentValue = currentValue * 16 + Integer.parseInt(String.valueOf(c), 16);
            } else {
                buffer.append(c);
            }
            lastC = c;
        }
        return buffer.toString();
    }

    /**
     * Given a key, the escape method returns the filename which shall be used.
     * 
     * @param key the key
     * @return the desired and escaped filename
     */
    protected String getName(final Object key) {
        return escape(key == null ? "\0" : key.toString()) + ".xml";
    }

    protected String escape(final String key) {
        // do we have a regex master to do it?
        final StringBuffer buffer = new StringBuffer();
        final char[] array = key.toCharArray();
        for (int i = 0; i < array.length; i++ ) {
            final char c = array[i];
            if (Character.isDigit(c) || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
                buffer.append(c);
            } else if (c == '_') {
                buffer.append("__");
            } else {
                buffer.append("_" + (Integer.toHexString(c)) + "_");
            }
        }
        return buffer.toString();
    }
}
