/*
 * Copyright (C) 1992 by Software Research Associates, Inc.
 *      Author: Y. Kawabe <kawabe@sra.co.jp>
 *
 * Permission to use, copy, modify, and distribute, and sell this software
 * and its documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be
 * used in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  Software Research Associates
 * makes no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 */

/*
 * class sjisCodeCvt
 */

#define sjisCodeCvt _lib_nls(sjisCodeCvt)

class sjisCodeCvt : public CodeCvt {
  public:
    sjisCodeCvt ();
    
  public:
    virtual CodeCvt* duplicate();
    virtual void setparam(const char*, const char*);

  public:
    virtual int get (istream&, WChar&);
    virtual int put (ostream&, const WChar&);
    
  protected:
    CharSet_T roman_ ;
    CharSet_T kana_ ;
    CharSet_T kanji_ ;
};

sjisCodeCvt::sjisCodeCvt () {
    roman_ = CharSet::ascii();
    kana_ = -1;
    kanji_ = -1;
}

CodeCvt* sjisCodeCvt::duplicate () {
    sjisCodeCvt *copy = new sjisCodeCvt ();
    *copy = *this;
    return copy;
}

void sjisCodeCvt::setparam (const char* key, const char* value) {
    if (strcmp (key, "GR") == 0) {
        roman_ = CharSet::find(value);
    } else if (strcmp (key, "GK") == 0) {
        kana_ = CharSet::find(value);
    } else if (strcmp (key, "GJ") == 0) {
        kanji_ = CharSet::find(value);
    }
}

//
// read WChar from input stream
//

int sjisCodeCvt::get (istream& is, WChar& wc) {
    register int	ch = is.get();
    if (ch != EOF) {
	if (is.good() && (ch >= 0x81 && ch <= 0x9f) ||
	    (ch >= 0xe0 && ch <= 0xfc)) { 
	    register int	ch2 = is.get();
	    register unsigned char c1 = ch, c2 = ch2;
	    
	    if (c1 >= 0xe0) c1 -= 0x40;
	    if (c2 >= 0x9f) {
		c1 = (c1 - 0x88) * 2 + 0x30;
		c2 = c2 - 0x7e;
	    } else {
		if (c2 >= 0x7f) c2 -= 0x01;
		c1 = (c1 - 0x89)* 2 + 0x31;
		c2 = c2 - 0x1f;
	    }
	    c1 &= 0x7f, c2 &= 0x7f;
	    wc.set((c1 << 8) | c2, kanji_);
	    return 2;
	} else if (ch > 0x7f) {
	    wc.set(ch & 0x7f, kana_);
	    return 1;
	} else if (ch <= 0x20) {
	    wc.set(ch, CharSet::ascii());
	    return 1;
	} else {
	    wc.set(ch, roman_);
	    return 1;
	}
    }
    return -1;				/* return EOF */
}

//
// write WChar to output stream
//

int sjisCodeCvt::put (ostream& os, const WChar& c) {
    if (c.value() == EOF) {
	return 0;
    } if (c.charset() == CharSet::ascii()) {
	os.put(c.charcode());
	return 1;
    } else if (c.charset() == roman_) {
	os.put(c.charcode());
	return 1;
    } else if (c.charset() == kana_) {
	os.put(c.charcode() | 0x80);
	return 1;
    } else if (c.charset() == kanji_) {
	register int code = c.charcode();
	register unsigned char c1 = (code>>8) & 0xff;
	register unsigned char c2 = code & 0xff;
       
	if(c1 >= 0x5f) c1 += 0x80;
	if((c1 % 2) == 0) {
	    c1 = ((c1 - 0x30) / 2 + 0x88) & 0xff;
	    c2 = (c2 + 0x7e) & 0xff;
	} else {                    
	    if(c2 >= 0x60) c2 = c2 + 0x01;
	    c1 = ((c1 - 0x31)/2 + 0x89) & 0xff;
	    c2 = (c2 + 0x1f) & 0xff;
	}
	os.put(c1);
	os.put(c2);
	return 2;
    }
    return 0;
}

