1/*
2 * Copyright (C) 2008 Esmertec AG.
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package com.android.im.imps;
18
19import java.nio.ByteBuffer;
20
21/**
22 * A helper class to split the payload into several segments to meet the size
23 * constraint of the sms.
24 *
25 */
26public class SmsSplitter {
27    private static final int MAX_SEGMENT_COUNT = 26;
28
29    private ByteBuffer mOutBuffer;
30    private int mMaxSegmentLen;
31
32    private byte[] mData;
33    private int mPreambleEnd;
34
35    private int mCurrentSegment;
36    private int mSegmentCount;
37
38    public SmsSplitter(int maxLen) {
39        mMaxSegmentLen = maxLen;
40        mOutBuffer = ByteBuffer.allocate(maxLen);
41    }
42
43    /**
44     * Split the data into several segments to meet the size constraint.
45     *
46     * @param data
47     *            The data to split. MUST be a valid PTS primitive.
48     * @return The count of segments of the result or -1 if the data is too long.
49     */
50    public int split(byte[] data) {
51        mData = data;
52        mCurrentSegment = 0;
53        calculateSegments();
54        if (mSegmentCount > MAX_SEGMENT_COUNT) {
55            mSegmentCount = -1;
56        }
57        return mSegmentCount;
58    }
59
60    public boolean hasNext() {
61        return mCurrentSegment < mSegmentCount;
62    }
63
64    /**
65     * Gets the next segment.
66     *
67     * @return The next segment.
68     * @throws IndexOutOfBoundsException
69     */
70    public byte[] getNext() {
71        if (mCurrentSegment >= mSegmentCount) {
72            throw new IndexOutOfBoundsException();
73        }
74        byte[] segment;
75        if (mSegmentCount == 1) {
76            segment = mData;
77        } else {
78            mOutBuffer.clear();
79            // The original preamble
80            mOutBuffer.put(mData, 0, mPreambleEnd);
81            // Two character of DD
82            mOutBuffer.put((byte) ('a' + mCurrentSegment));
83            mOutBuffer.put((byte) ('a' + mSegmentCount - 1));
84            // The space after preamble
85            mOutBuffer.put((byte) ' ');
86
87            // The payload
88            int segmentPayload = mMaxSegmentLen - mPreambleEnd - 3;
89            int offset = mPreambleEnd + 1 + segmentPayload * mCurrentSegment;
90            int len = (offset + segmentPayload > mData.length) ?
91                    mData.length - offset : segmentPayload;
92            mOutBuffer.put(mData, offset, len);
93
94            mOutBuffer.flip();
95            segment = new byte[mOutBuffer.limit()];
96            mOutBuffer.get(segment);
97        }
98        mCurrentSegment++;
99        return segment;
100    }
101
102    private void calculateSegments() {
103        int totalLen = mData.length;
104        if (totalLen < mMaxSegmentLen) {
105            mSegmentCount = 1;
106        } else {
107            searchPreambleEnd();
108            int newPreambleLen = mPreambleEnd + 2;
109            int segmentPayload = mMaxSegmentLen - newPreambleLen - 1;
110            int totalPayload = totalLen - mPreambleEnd - 1;
111            mSegmentCount = (totalPayload + segmentPayload -1) / segmentPayload;
112        }
113    }
114
115    private void searchPreambleEnd() {
116        byte[] data = mData;
117        int index = 0;
118        while(index < data.length && data[index] != ' ') {
119            index++;
120        }
121        mPreambleEnd = index;
122    }
123}