/*
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2005 satoshi akabane(akabane@logical-paradox.org)
 * $Id: store.java,v 1.2 2005/09/07 13:38:06 rampil Exp $
 */
package org.logical_paradox.vsan.tools.console.command;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import org.logical_paradox.common.io.ExpandableBuffer;
import org.logical_paradox.shell.Argument;
import org.logical_paradox.shell.Command;
import org.logical_paradox.shell.Option;
import org.logical_paradox.shell.ResultCode;
import org.logical_paradox.shell.ShellEnv;
import org.logical_paradox.shell.exception.CommandExecutionException;
import org.logical_paradox.shell.exception.TerminationException;
import org.logical_paradox.vsan.dac.Response;
import org.logical_paradox.vsan.dac.ResponseCode;
import org.logical_paradox.vsan.dac.command.Protocol;
import org.logical_paradox.vsan.tools.console.DacConsoleConstant;
import org.logical_paradox.vsan.tools.console.util.SocketWriter;

/**
 * <pre>
 * ■store
 * 
 * 【動作仕様】
 * DACに対して、データを送信します。
 * このコマンドは、dacコマンドによって設定された'dac'環境変数を参照します。
 * 
 * 【書式】
 * store {--text=<text> | --bin=<binary stream>} --record=<record no.> [<hostname>[:<port>]]
 * 
 * </pre>
 * 
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.2 $
 */
public class store implements Command {
	public static final String USAGE = "store {--text=<text> | --bin=<binary stream>} --record=<record no.> [<hostname>[:<port>]]";

	public String usage() {
		return USAGE;
	}

	public ResultCode execute(OutputStream o, ShellEnv env, Argument a) throws CommandExecutionException, TerminationException {
		String dac = null;

		if(a == null || a.getArguments().length == 0) {
			dac = env.getProperty(DacConsoleConstant.ENV_DAC);
		} else if(a.getArguments().length > 1) {
			throw new CommandExecutionException();
		} else {
			dac = a.getArguments()[0];
		}

		// オプションの解析
		ExpandableBuffer exb = new ExpandableBuffer();

		long rno = -1;

		try {
			Option[] options = a.getOptions();
			for(int i = 0; i < options.length; i++) {
				Option option = options[i];
				if("text".equals(option.getName())) {
					exb.write(option.getValue().getBytes());
				} else if("bin".equals(option.getName())) {
					exb.write(getByteStream(option.getValue()));
				} else if("record".equals(option.getName())) {
					rno = Integer.parseInt(option.getValue());
				}
			}

			if(exb.size() == 0 || rno < 0) {
				throw new CommandExecutionException();
			}

			ByteBuffer bb = ByteBuffer.allocate(1 + 8 + 4 + exb.size()).order(ByteOrder.BIG_ENDIAN);
			bb.put((byte)Protocol.P_STORE);
			bb.putLong(rno);
			bb.putInt(exb.using());
			bb.put(exb.byteStream());

			PrintWriter pw = new PrintWriter(o);
			pw.println("storing data..\n");

			Response response = SocketWriter.send(dac, bb.array(), false);

			if(response.getResponseCode() == ResponseCode.OK) {
				// 実行ステータスがOKの場合
				pw.println("done.");
				pw.flush();
				pw.close();

				return new ResultCode(ResultCode.STATUS_OK);
			} else {
				// 実行ステータスコードがOK以外の場合
				pw.println("fatal error is caused in executing STORE command: code=[" + response.getResponseCode() + "]\n");
				pw.flush();
				pw.close();

				return new ResultCode(ResultCode.STATUS_ERROR);
			}
		} catch(IOException e) {
			throw new CommandExecutionException();
		}
	}
	/**
	 * 文字列として与えられたバイト列を，本当のバイト列に変換して返す
	 * 16真数で半角カンマ区切りとする
	 * @param bstr バイト列の文字列表現
	 * @return 変換されたバイト列
	 */	
	protected byte[] getByteStream(String bstr) {
		String[] bytes = bstr.split(",");
		byte[] rc = new byte[bytes.length];

		for(int i = 0; i < bytes.length; i++) {
			rc[i] = Integer.decode("0x" + bytes[i]).byteValue();
		}

		return rc;
	}
}
