#pragma once
#include "string_aligner.hpp"

class HexForm
{
	long m_value;
	unsigned m_width;
	char m_filler;
	bool m_upper;
	bool m_valid_sign;
	
	HexForm(const HexForm& that);
public:
	HexForm(long value=0, unsigned width=4)
			:m_value(value),
			 m_width(width),
			 m_filler('0'),
			 m_upper(true),
			 m_valid_sign(true)
	{
	}
	
	HexForm(std::string str)
			:m_value(0),
			 m_width(4),
			 m_filler('0'),
			 m_upper(true),
			 m_valid_sign(false)
	{
		read(str);
	}
	/** get the string */
	std::string to_s()const { return string(); }
	long to_i() const { return m_value; }
	HexForm& filler(char c) { m_filler = c; return *this; }
	HexForm& width(unsigned w) { m_width = w; return *this; }
	HexForm& upper() { m_upper = true; return *this; }
	HexForm& lower() { m_upper = false; return *this; }
	friend std::ostream& operator<<(std::ostream& os, const HexForm& rh)
	{
		os << rh.to_s();
		return os;
	}
	
	HexForm& read(std::string str)
	{
		long value=0;
		int sign=1;
		for (unsigned i=0; i<str.length(); ++i){
			char c = str[i];
			if (isdigit(c)){
				value<<=4;
				value += (c - '0');
			} else if (('a'<= c && c<='f')){
				value<<=4;
				value += (c - 'a') + 10;
				m_upper=false;
			} else if ('A'<= c && c<='F'){
				value<<=4;
				value += (c - 'A') + 10;
				m_upper=true;
			} else if (c == 'x' || c=='X'
					   || c=='$' || c == '#' || c == '+' ) {
				continue;
			} else if (c == '-') {
				if (i == 0) {
					sign = -1;
				}
			} else {
				break;
			}
			m_valid_sign=true;
		}
		m_value = value * sign;
		return *this;
	}
	std::string string()const
	{
		std::string content="";
		std::string sign_str="";
		long value = m_value;
		if (m_value < 0) {
			value = - m_value;			
			sign_str="-";
		}
		for (long v=value; v>0; v>>=4){
			char c = v & 0x0F;
			if (c < 10){
				c += '0';
				content = c + content;
			} else {
				c += (m_upper ? 'A':'a') - 10;
				content = c + content;
			}
		}
		if (m_value == 0){
			content = "0";
		}
		if (m_valid_sign == false) {
			StringRepeat invalid('-');
			return invalid * m_width;
		}
		StringAligner right(m_width, StringAligner::RIGHT, m_filler);
		if (m_filler == ' ') {
			return right(sign_str+content);
		} else {
			return sign_str + right(content);
		}
	}
};
