/*
 *	Example:
 *	var length int64 = 0
 *		// Get the length of copyFile
 *		lbr, _ := c.GetBucket("xxxx", "", "", "", "100")
 *		l := len(lbr.Contents)
 *		for i := 0; i < l; i++ {
 *			if (lbr.Contents[i].Key) == "test.pdf" {
 *				size := lbr.Contents[i].Size
 *				length = int64(size)
 *			}
 *		}
 *	isLastPart, end, cpr, cmu, err = c.UploadPartCopy(imur, initObjectPath, "xxxx/test.pdf", cmu, end, 1048576(1MB), length, i)
 *
 *	If file size is smaller than 1GB, please use function CopyObject.
 */
func (c *Client) UploadPartCopy(imur types.InitiateMultipartUploadResult, initObjectPath, copySrc string, cmu types.CompleteMultipartUpload, start, chunkSize, length int64, partNumber int) (isLastPart bool, end int64, cpr types.CopyPartResult, cmuNew types.CompleteMultipartUpload, err error) {
	cc := c.CClient

	if strings.HasPrefix(copySrc, "/") == false {
		copySrc = "/" + copySrc
	}
	if strings.HasPrefix(initObjectPath, "/") == false {
		initObjectPath = "/" + initObjectPath
	}

	if partNumber < 1 {
		partNumber = 1
	}

	if chunkSize < 102400 {
		chunkSize = 102400 // min 100KB
	}

	if length <= (start + chunkSize) {
		chunkSize = length - start
		end = length - 1
		isLastPart = true
	} else {
		end = start + chunkSize
		isLastPart = false
	}

	reqStr := initObjectPath + "?partNumber=" + strconv.Itoa(partNumber) + "&uploadId=" + imur.UploadId

	params := map[string]string{consts.OH_COPY_OBJECT_SOURCE: copySrc}
	params[consts.OH_COPY_SOURCE_RANGE] = "bytes=" + strconv.Itoa(int(start)) + "-" + strconv.Itoa(int(start+chunkSize-1))

	resp, err := cc.DoRequest("PUT", reqStr, reqStr, params, nil)
	if err != nil {
		return
	}

	body, _ := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		err = errors.New(resp.Status)
		log.Println(string(body))
		return
	}

	err = xml.Unmarshal(body, &cpr)
	newPart := types.Part{}
	newPart.ETag = cpr.ETag
	newPart.PartNumber = partNumber
	cmuNew.Part = append(cmu.Part, newPart)

	//log.Println("Partnumber " + strconv.Itoa(partNumber) + " of the " + initObjectPath + " has been copied.")
	return

}
/*
 *	Example:
 *	isLastPart, end, cmuNew, err := c.UploadPart(imur, initobjectPath, filePath, cmu, start, chunkSize, partNumber)
 *
 *	chunkSize must be larger than 102400
 *	If chunkSize is smaller than 102400, chunkSize will be 102400
 */
func (c *Client) UploadPart(imur types.InitiateMultipartUploadResult, initObjectPath, filePath string, cmu types.CompleteMultipartUpload, start, chunkSize int64, partNumber int) (isLastPart bool, end int64, cmuNew types.CompleteMultipartUpload, err error) {
	cc := c.CClient

	file, err := os.Open(filePath)
	if err != nil {
		return
	}
	defer file.Close()
	bufferLength := new(bytes.Buffer)
	io.Copy(bufferLength, file)
	buffer := new(bytes.Buffer)

	length := int64(bufferLength.Len())

	if partNumber < 1 {
		partNumber = 1
	}

	if chunkSize < 102400 {
		chunkSize = 102400
	}

	if length < (start + chunkSize - 1) {
		chunkSize = length - start
		end = length - 1
		isLastPart = true
	} else {
		end = start + chunkSize
		isLastPart = false
	}

	bufCutFile := make([]byte, chunkSize)

	file.ReadAt(bufCutFile, start)
	var i int64 = 0
	for i = 0; i < chunkSize; i++ {
		buffer.WriteByte(bufCutFile[i])
	}

	if strings.HasPrefix(initObjectPath, "/") == false {
		initObjectPath = "/" + initObjectPath
	}

	reqStr := initObjectPath + "?partNumber=" + strconv.Itoa(partNumber) + "&uploadId=" + imur.UploadId

	resp, err := cc.DoRequest("PUT", reqStr, reqStr, nil, buffer)
	if err != nil {
		return
	}

	body, _ := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		err = errors.New(resp.Status)
		log.Println(string(body))
		return
	}

	newPart := types.Part{}
	newPart.ETag = resp.Header.Get(consts.HH_ETAG)
	newPart.PartNumber = partNumber
	cmuNew.Part = append(cmu.Part, newPart)

	//log.Println("Part number " + strconv.Itoa(partNumber) + " of the " + initObjectPath + " has been uploaded.")
	return

}