package gov.nist.javax.sip.message;

import gov.nist.javax.sip.header.HeaderFactoryExt;
import gov.nist.javax.sip.header.HeaderFactoryImpl;
import gov.nist.javax.sip.parser.StringMsgParser;

import java.text.ParseException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.sip.header.ContentDispositionHeader;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.Header;
import javax.sip.header.HeaderFactory;
import javax.sip.message.Message;



/**
 * Content list for multipart mime content type.
 * 
 * @author M. Ranganathan
 * 
 */
public class MultipartMimeContentImpl implements MultipartMimeContent {
    private List<Content> contentList = new LinkedList<Content>();

    private ContentTypeHeader multipartMimeContentTypeHeader;

    private String boundary;

    public static String BOUNDARY = "boundary";

    /**
     * Creates a default content list.
     */
    public MultipartMimeContentImpl(ContentTypeHeader contentTypeHeader) {
        this.multipartMimeContentTypeHeader = contentTypeHeader;
        this.boundary = contentTypeHeader.getParameter(BOUNDARY);

    }

    /*
     * (non-Javadoc)
     * 
     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#add(gov.nist.javax.sip.message.Content)
     */
    public boolean add(Content content) {
        return contentList.add((ContentImpl) content);
    }

    /*
     * (non-Javadoc)
     * 
     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#getContentTypeHeader()
     */
    public ContentTypeHeader getContentTypeHeader() {
        return multipartMimeContentTypeHeader;
    }

    /*
     * (non-Javadoc)
     * 
     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#toString()
     */
    @Override
    public String toString() {
        StringBuffer stringBuffer = new StringBuffer();

        for (Content content : this.contentList) {
            stringBuffer.append(content.toString());
        }
        return stringBuffer.toString();

    }

    /**
     * unpack a multipart mime packet and return a list of content packets.
     * 
     * @return -- an iterator of Content blocks.
     * 
     */
    public void createContentList(String body) throws ParseException {
        try {
            HeaderFactoryExt headerFactory = new HeaderFactoryImpl();
            String delimiter = this.getContentTypeHeader().getParameter(BOUNDARY);

            if (delimiter == null) {
                this.contentList = new LinkedList<Content>();
                ContentImpl content = new ContentImpl(body, delimiter);
                content.setContentTypeHeader(this.getContentTypeHeader());
                this.contentList.add(content);
                return;
            }

            String[] fragments = body.split("--" + delimiter + "\r\n");


            for (String nextPart : fragments) {
                // NOTE - we are not hanlding line folding for the sip header here.

                if (nextPart == null) {
                    return;
                }
                StringBuffer strbuf = new StringBuffer(nextPart);
                while (strbuf.length() > 0
                        && (strbuf.charAt(0) == '\r' || strbuf.charAt(0) == '\n'))
                    strbuf.deleteCharAt(0);

                if (strbuf.length() == 0)
                    continue;
                nextPart = strbuf.toString();
                int position = nextPart.indexOf("\r\n\r\n");
                int off = 4;
                if (position == -1) {
                    position = nextPart.indexOf("\n");
                    off = 2;
                }
                if (position == -1)
                    throw new ParseException("no content type header found in " + nextPart, 0);
                String rest = nextPart.substring(position + off);

                if (rest == null)
                    throw new ParseException("No content [" + nextPart + "]", 0);
                // logger.debug("rest = [[" + rest + "]]");
                String headers = nextPart.substring(0, position);
                ContentImpl content = new ContentImpl(rest, boundary);

                String[] headerArray = headers.split("\r\n");
                for (String hdr : headerArray) {
                    Header header = headerFactory.createHeader(hdr);
                    if (header instanceof ContentTypeHeader) {
                        content.setContentTypeHeader((ContentTypeHeader) header);
                    } else if (header instanceof ContentDispositionHeader) {
                        content.setContentDispositionHeader((ContentDispositionHeader) header);
                    } else {
                        throw new ParseException("Unexpected header type " + header.getName(), 0);
                    }
                    contentList.add(content);
                }

            }
        } catch (StringIndexOutOfBoundsException ex) {
            throw new ParseException("Invalid Multipart mime format", 0);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#getContentByType(java.lang.String,
     *      java.lang.String)
     */
    public Content getContentByType(String contentType, String contentSubtype) {
        Content retval = null;
        if (contentList == null)
            return null;
        for (Content content : contentList) {
            if (content.getContentTypeHeader().getContentType().equalsIgnoreCase(contentType)
                    && content.getContentTypeHeader().getContentSubType().equalsIgnoreCase(
                            contentSubtype)) {
                retval = content;
                break;
            }

        }
        return retval;
    }

    /*
     * (non-Javadoc)
     * 
     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#setContent(java.lang.String,
     *      java.lang.String, gov.nist.javax.sip.message.Content)
     */
    public void addContent(Content content) {
        this.add(content);
    }

    public Iterator<Content> getContents() {
        return this.contentList.iterator();
    }

    
    public int getContentCount() {
        return this.contentList.size();
    }

}