text: package org.java_websocket.framing;
  
  import java.nio.ByteBuffer;
  
  import org.java_websocket.exceptions.InvalidDataException;
  import org.java_websocket.exceptions.InvalidFrameException;
  import org.java_websocket.util.Charsetfunctions;
  
  public class CloseFrameBuilder extends FramedataImpl1 implements CloseFrame {
  
  	static final ByteBuffer emptybytebuffer = ByteBuffer.allocate( 0 );
  
  	private int code;
  	private String reason;
  
  	public CloseFrameBuilder() {
  		super( Opcode.CLOSING );
  		setFin( true );
  	}
  
  	public CloseFrameBuilder( int code ) throws InvalidDataException {
  		super( Opcode.CLOSING );
  		setFin( true );
  		setCodeAndMessage( code, "" );
  	}
  
  	public CloseFrameBuilder( int code , String m ) throws InvalidDataException {
  		super( Opcode.CLOSING );
  		setFin( true );
  		setCodeAndMessage( code, m );
  	}
  
  	private void setCodeAndMessage( int code, String m ) throws InvalidDataException {
  		if( m == null ) {
  			m = "";
  		}
  		// CloseFrame.TLS_ERROR is not allowed to be transfered over the wire
  		if( code == CloseFrame.TLS_ERROR ) {
  			code = CloseFrame.NOCODE;
  			m = "";
  		}
  		if( code == CloseFrame.NOCODE ) {
  			if( 0 < m.length() ) {
  				throw new InvalidDataException( PROTOCOL_ERROR, "A close frame must have a closecode if it has a reason" );
  			}
  			return;// empty payload
  		}
  
  		byte[] by = Charsetfunctions.utf8Bytes( m );
  		ByteBuffer buf = ByteBuffer.allocate( 4 );
  		buf.putInt( code );
  		buf.position( 2 );
  		ByteBuffer pay = ByteBuffer.allocate( 2 + by.length );
  		pay.put( buf );
  		pay.put( by );
  		pay.rewind();
  		setPayload( pay );
  	}
  
  	private void initCloseCode() throws InvalidFrameException {
  		code = CloseFrame.NOCODE;
  		ByteBuffer payload = super.getPayloadData();
  		payload.mark();
  		if( payload.remaining() >= 2 ) {
  			ByteBuffer bb = ByteBuffer.allocate( 4 );
  			bb.position( 2 );
  			bb.putShort( payload.getShort() );
  			bb.position( 0 );
  			code = bb.getInt();
  
  			if( code == CloseFrame.ABNORMAL_CLOSE || code == CloseFrame.TLS_ERROR || code == CloseFrame.NOCODE || code > 4999 || code < 1000 || code == 1004 ) {
  				throw new InvalidFrameException( "closecode must not be sent over the wire: " + code );
  			}
  		}
  		payload.reset();
  	}
  
  	@Override
  	public int getCloseCode() {
  		return code;
  	}
  
  	private void initMessage() throws InvalidDataException {
  		if( code == CloseFrame.NOCODE ) {
  			reason = Charsetfunctions.stringUtf8( super.getPayloadData() );
  		} else {
  			ByteBuffer b = super.getPayloadData();
  			int mark = b.position();// because stringUtf8 also creates a mark
  			try {
  				b.position( b.position() + 2 );
  				reason = Charsetfunctions.stringUtf8( b );
  			} catch ( IllegalArgumentException e ) {
  				throw new InvalidFrameException( e );
  			} finally {
  				b.position( mark );
  			}
  		}
  	}
  
  	@Override
  	public String getMessage() {
  		return reason;
  	}
  
  	@Override
  	public String toString() {
  		return super.toString() + "code: " + code;
  	}
  
  	@Override
  	public void setPayload( ByteBuffer payload ) throws InvalidDataException {
  		super.setPayload( payload );
  		initCloseCode();
  		initMessage();
  	}
  	@Override
  	public ByteBuffer getPayloadData() {
  		if( code == NOCODE )
  			return emptybytebuffer;
  		return super.getPayloadData();
  	}
  
  }
  