void decSize(vector<char>& head, int m){
	vector<char> temp;
	for (int i = 0; i < 4; i++)
		temp.push_back(head[i]);
	int n = char4ToInt(temp);
	n -= m;
	intToChar4(n, temp);
	for (int i = 0; i < 4; i++)
		head[i] = temp[i];
}
Address RecordManager::insertRecord(vector<char>& newRecord, string fileName, int recordSize){
	Address addr(fileName, 0, 0);
	Address head(fileName, 0, 0);//head
	vector<char> headRecord;

	vector<char> nextBlock;
	vector<char> nextOffset;

	int newBlock;
	int newOffset;
	int headSize;
	if (recordSize < 20)
		headSize = 20;
	else
		headSize = recordSize;

	///////文件中无记录///////
	if (bmanager.getFileBlockNumber(fileName) == 0){
		bmanager.createFile(fileName);
		
		//清空文件头
		newHead(headRecord, headSize);

		//新纪录位置(0,1)
		newBlock = 0;
		newOffset = headSize;

		//新纪录指向head(不用改了,default)
	}
	else{
		headRecord = bmanager.read(head, headSize);
		int size = getSize(headRecord);
		if (size == 0){
			//清空文件头
			newHead(headRecord, headSize);

			//新纪录位置(0,1)
			newBlock = 0;
			newOffset = headSize;

			//新纪录指向head(不用改了,default)
		}
		///////文件中有记录///////
		else{
			//新纪录位置
			setNextAddr(headRecord, nextBlock, nextOffset, headSize- 16);//第一条被删的记录
			int delBlock = char4ToInt(nextBlock);
			int delOffset = char4ToInt(nextOffset);
			
			if (delBlock == 0 && delOffset == 0){//没有被删记录
				int n;//一块中的记录数
				int block = bmanager.getFileBlockNumber(fileName) - 1;
				int offset;
				int size = getSize(headRecord);//文件中的记录数(不包括head)
				if (block == 0){
					n = (4096 - headSize) / recordSize;//第一块中的record数
					if (size == n){
						newBlock = block + 1;
						newOffset = 0;
					}
					else{//size<n
						newBlock = block;
						newOffset = headSize + (size%n)*recordSize;
					}
				}
				else{
					n = 4096 / recordSize;//其他块中最多能放的record数
					if (size == (4096 - headSize) / recordSize+block*n){
						newBlock = block + 1;
						newOffset = 0;
					}
					else{
						newBlock = block;
						newOffset = ((size - (4096 - headSize) / recordSize) % n)*recordSize;
					}
				}
			}
			else{///有被删记录
				//空位在(delBlock,delOffset)
				newBlock = delBlock;
				newOffset = delOffset;
				//修改文件头中的del指针,使它指向第二条被删记录
				addr.setAddr(fileName, delBlock, delOffset);
				vector<char> tempRecord = bmanager.read(addr, recordSize);
				setNextAddr(tempRecord, nextBlock, nextOffset, recordSize - 8);
				updateRecordPoint(headRecord, nextBlock, nextOffset, headSize - 16);
			}
			
			//newRecord指向第一条记录
			setNextAddr(headRecord, nextBlock, nextOffset, headSize - 8); 
			updateRecordPoint(newRecord, nextBlock, nextOffset, recordSize - 8);
		}
	}
	
	//插入新记录
	
	addr.setAddr(fileName, newBlock, newOffset);
	bmanager.write(addr, newRecord);//√
	//更新head
	//head指向第一条记录
	intToChar4(newBlock, nextBlock);
	intToChar4(newOffset, nextOffset);
	updateRecordPoint(headRecord, nextBlock, nextOffset, headSize - 8);
	//更新head中的size
	incSize(headRecord);
	//写回headRecord
	bmanager.write(head, headRecord);//√

	return addr;
}
int API::select(const string tableName, const vector<string> &attr, const vector<string> &op, const vector<string> &value,
	const vector<int>& type, const vector<int>& begin, int recordSize, vector<vector<char>>& returnRecord, int toDelete){
	vector<int> end;
	vector<char> temp;
	vector<vector<char>> valuex;
	vector<int> opx;
	vector<Address> returnAddr;
	if (op.size()==0){//selete * from xxx;//无条件
		if (toDelete){
			//判断有无索引
			vector<char> tName;
			sToVchar(tableName, tName);
			vector<vector<char>> returnRecord;
			vector<int> op; op.push_back(0);
			vector<vector<char>> value; value.push_back(tName);
			vector<int> begin; begin.push_back(50);
			vector<int> end; end.push_back(100);
			vector<int> type; type.push_back(53);
			Index index;
			rmanager.findAllRecord("index.catalog", op, value, begin, end, type, index.recordSize, returnRecord, 0);
			for (int i = 0; i < returnRecord.size(); i++){//若有 则清空索引文件
				string temp = "";
				for (int j = 0; j < 50; j++)
					if (returnRecord[i][j])
						temp += returnRecord[i][j];
				//bmanager.deleteFile(temp + ".index");
				//cmanager.clearFile(temp + ".index");
					
					imanager.rebuildIndex(temp);
			}
			return rmanager.deleteAll(tableName, recordSize);
		}
		else{
			//cout << "okok" << endl;
			returnAddr=rmanager.getAllRecord(tableName, recordSize, returnRecord);
			//cout << "okok" << endl;
			return returnAddr.size();
		}
	}
	else{//有条件
		for (int i = 0; i < op.size(); i++){
			if (type[i] == 1){//int
				end.push_back(begin[i] + 4);
				intToChar4(atoi(value[i].c_str()), temp);
				valuex.push_back(temp);
				opx.push_back(typeToInt(op[i]));
			}
			else if (type[i] == 2){//float
				end.push_back(begin[i] + 4);
				floatToChar4(atof(value[i].c_str()), temp);
				valuex.push_back(temp);
				opx.push_back(typeToInt(op[i]));
			}
			else{//char(n)
				end.push_back(begin[i] + type[i]-3);
				temp.clear();
				for (int k = 0; k < value[i].size(); k++)
					temp.push_back(value[i][k]);
				//sToVchar(value[i], temp);
				valuex.push_back(temp);
				opx.push_back(typeToInt(op[i]));
			}
		}
		
		//判断属性是否都有索引
		vector<int> in;
		vector<string> attrHasIndex;

		Index index;
		string indexName;
		int useIndex = 1;
		vector<char> key;
		vector<char> key1;
		sToVchar(tableName, key);
		for (int i = 0; i < attr.size(); i++){
			int flag = 0;
			for (int j = 0; j < attrHasIndex.size(); j++)//查找这个属性有无在attrHasIndex中
				if (attr[i] == attrHasIndex[j]){
					flag = 1;
					break;
				}
			if (flag)
				continue;
			
			//查找这个属性上有无index
			key.erase(key.begin() + 50, key.end());
			sToVchar(attr[i], key1);
			key.insert(key.end(), key1.begin(), key1.end());
			Address addr = rmanager.findLastRecord("index.catalog", key, index.recordSize, 50);
			if (addr.isNullAddr()){//条件中有一个属性没有索引
				//cout << attr[i] << ": no index!" << endl;
				useIndex = 0;
				break;
			}
			else{//有索引
				//cout << attr[i] << ": index!" << endl;
				temp = rmanager.getNextRecord(addr, "index.catalog", index.recordSize);
				indexName = "";
				for (int i = 0; i < 50; i++){
					if (temp[i])
						indexName += temp[i];
				}
				attrHasIndex.push_back(indexName);
				in.push_back(i);
			}

		}

		//选择select方式
		if (!useIndex||attrHasIndex.size()>1){
			clock_t start = clock();
			returnAddr = rmanager.findAllRecord(tableName, opx, valuex, begin, end, type, recordSize, returnRecord, toDelete);
			clock_t finish = clock();
			printf("Time consumed: %f second\n", (double)(finish - start) / CLOCKS_PER_SEC);
		}
		else{//符合使用index加速的条件
			if (toDelete == 0){//select
				cout << "use index" << endl;
				clock_t start = clock();
				/*for (int i = 0; i < valuex.size(); i++)
					printvc(valuex[i]);*/
				returnAddr = imanager.select(indexName, valuex, opx);
				//cout << "ok" << endl;
				returnRecord.clear();
				for (int i = 0; i < returnAddr.size(); i++){
					returnAddr[i].setAddrFile(tableName);
					returnRecord.push_back(rmanager.getRecord(returnAddr[i], recordSize));
				}
				clock_t finish = clock();
				printf("Time consumed: %f second\n", (double)(finish - start) / CLOCKS_PER_SEC);

			}
			else{//delete
				returnAddr = rmanager.findAllRecord(tableName, opx, valuex, begin, end, type, recordSize, returnRecord, toDelete);

				for (int i = 0; i < attrHasIndex.size(); i++)
					for (int j = 0; j < returnRecord.size(); j++)
						imanager.deleteKey(attrHasIndex[i], subVector(returnRecord[j], begin[in[i]], end[in[i]]));				
			}
		}

		//returnAddr = rmanager.findAllRecord(tableName, opx, valuex, begin, end, type, recordSize, returnRecord, toDelete);
			
		return returnAddr.size();
	}
}
void processInput(int connfd, unsigned int secretKey) {
    size_t size;
    //buffers required by all commands
    unsigned char *secretKeyBuf = (unsigned char*)malloc(sizeof(char) * 4);
    unsigned char *requestBuf = (unsigned char*)malloc(sizeof(char) * 4);

    //get and put
    unsigned char *fileSizeBuf = (unsigned char*)malloc(sizeof(char) * 4);
    char *fileNameBuf = (char*)malloc(sizeof(char) * 80);
    char *fileContentsBuf;

    //list buffers
    unsigned char *returnListBuf;

    //return buffers
    unsigned char *returnCodeBuf = (unsigned char*)malloc(sizeof(char) * 4);
    unsigned char *returnSizeCodeBuf = (unsigned char*)malloc(sizeof(char) * 4);

    //RIO stuff
    rio_t rio;
    Rio_readinitb(&rio, connfd);

    //ints parsed from buffers
    unsigned int nsecretKey, request, fileSize;
    unsigned int bufferSize = 0; //for EOF
    //bools used for method logic (not necessary, but helps with reading the file)
    bool shouldUseFilename = false, error = false, list = false, get = false, put = false, del = false;
    
    //read in the secret key and type of request.
    size = Rio_readnb(&rio, secretKeyBuf, 4);
    if(size!=4){
        error = true;
    }
    size = Rio_readnb(&rio, requestBuf, 4);
    if(size!=4){
        error = true;
    }

    //convert the secret key and request buffers to ints
    nsecretKey = char4ToInt(secretKeyBuf);
    request = char4ToInt(requestBuf);
    printf("Secret Key = %d\n", nsecretKey);
    printf("Request Type = ");

    //check the secret keys and set error
    if (nsecretKey != secretKey)
    {
        error = true;
    }

    //print some stuff to the console depending on what command is requested
    switch(request) {
        case 0:
            //get
            printf("get\n");
            printf("Filename = ");
            shouldUseFilename = true;
            get = true;
            break;
        case 1:
            //put
            printf("put\n");
            printf("Filename = ");
            shouldUseFilename = true;
            put = true;
            break;
        case 2:
            //del
            printf("del\n");
            printf("Filename = ");
            shouldUseFilename = true;
            del = true;
            break;
        case 3:
            //list
            printf("list\n");
            printf("Filename = NONE\n");
            list = true;
            break;
        default:
            printf("undefined: %d\n",request);
            printf("Filename = NONE\n");
            error = true;
            break;
    }
    //if the command we're utilizing receives a filename, read it in.
    if (shouldUseFilename) {
        size = Rio_readnb(&rio, fileNameBuf, 80);
        printf("%s\n",fileNameBuf);
    }
    if (put && !error) {
        size = Rio_readnb(&rio, fileSizeBuf, 4);
        fileSize = char4ToInt(fileSizeBuf);
        //printf("Creating file buf of size %d\n",fileSize);
        fileContentsBuf = (char*)malloc(sizeof(char) * (fileSize+1));
        size = Rio_readnb(&rio, fileContentsBuf, fileSize);

        FILE *stream;
        char filePath[100];
        //create the file path
        strcpy(filePath, "./files/");
        strcat(filePath, fileNameBuf);
        if ((stream = fopen(filePath, "w")))
        {
            //write the file
            fwrite(fileContentsBuf, 1, fileSize, stream);
            //Debug print
            //printf("Write: %s\n",fileContentsBuf);
            fclose(stream);
        } else {
            //an error occurred writing the file
            perror("Put file");
            error = true;
        }
    }
    if (list && !error)
    {
         //for end of file
        DIR *d, *e;
        struct dirent *dir;
        //open the files directory
        d = opendir("./files");
        if (d)
        {
            while ((dir = readdir(d)) != NULL)
            {
                if (dir->d_type == DT_REG)
                {
                    //count up the length of each filename (for the length byte)
                    bufferSize += strlen(dir->d_name);
                    bufferSize += 1;
                }
            }
        }
        closedir(d);
        returnListBuf = (unsigned char*)malloc(sizeof(char) * bufferSize);
        e = opendir("./files");
        int counter = 0;
        if (e)
        {
            while ((dir = readdir(e)) != NULL)
            {
                if (dir->d_type == DT_REG)
                {
                    //print each name to a buffer
                    //printf("%s\n",dir->d_name);
                    char temp[strlen(dir->d_name) + 1];
                    sprintf(temp,"%s\n",dir->d_name);
                    memcpy(&returnListBuf[counter], temp, strlen(temp));
                    counter += strlen(temp);
                    // printf("%s\n", dir->d_name);   
                }
            }
        }
    }
    if(get && !error){
        FILE *stream;
        fileSize = 0;
        char filePath[100];
        strcpy(filePath, "./files/");
        strcat(filePath, fileNameBuf);
        //try to open the file (in the files directory)
        if ((stream = fopen(filePath, "rb")))
        {
            //Seek to the end of the file to determine the file size
            fseek(stream, 0L, SEEK_END);
            fileSize = ftell(stream);
            fseek(stream, 0L, SEEK_SET);
            //printf("fileSize: %d\n",fileSize);
            fileContentsBuf = (char*)malloc(sizeof(char) * (fileSize+1));
            size=fread(fileContentsBuf,1,fileSize,stream);
            fileContentsBuf[size]=0; //add EOF
            //Debug print
            //printf("Read: %s\n",fileContentsBuf);
            //printf("Size T: %lu\n", size);
            fclose(stream);
        } else {
            //an error occurred opening the file. It may not exist, or permissions aren't set
            perror("Open file");
            error = true;
        }
    }
    if(del && !error){
        char filePath[100];
        strcpy(filePath, "./files/");
        strcat(filePath, fileNameBuf);
        //delete the file at path
        //printf("deleting file at path: %s\n",filePath);
        int delResult = unlink(filePath);
        if(delResult != 0){
            error = true;
        }
    }
    //all input should be read in now. Now to handle the files themselves
    unsigned int returnCode;
    if(error){
        returnCode = -1;
        printf("Operation Status = error\n");
    } else{
        returnCode = 0;
        printf("Operation Status = success\n");
    }
    intToChar4(returnCode, returnCodeBuf);
    Rio_writen(connfd, returnCodeBuf, 4);
    //printf("sent\n");

    //only send the get and list info if there isn't an error
    if(!error){
        switch(request) {
            case 0:
                //get
                //bufferSize = strlen(fileContentsBuf) + 1;
                //printf("Size of file: %lu\n",size);
                intToChar4(size, returnSizeCodeBuf);
                Rio_writen(connfd, returnSizeCodeBuf, 4);
                Rio_writen(connfd, fileContentsBuf, size);
                // for (unsigned int i = 0; i < size; ++i)
                // {
                //     printf("%02x",fileContentsBuf[i]);
                // }
                break;
            case 3:
                //list
                //printf("Size of files list: %d\n",bufferSize);
                intToChar4(bufferSize, returnSizeCodeBuf);
                Rio_writen(connfd, returnSizeCodeBuf, 4);
                Rio_writen(connfd, returnListBuf, bufferSize);
                break;
            default:
                break;
        }
    }

    printf("--------------------------\n");
}
int API::insert(const string tableName, const vector<string>& value,const vector<int>& type){
	vector<char> temp;
	vector<char> valueForBtree;
	vector<char> tName;
	int k = -1;
	sToVchar(tableName, tName);
	Index index;
	string attrHasIndex = "";
	string indexName = "";
	Address addr = rmanager.findLastRecord("index.catalog", tName, index.recordSize, 50);
	if (addr.isNullAddr())//如果这个表上没有索引
		;
	else{
		temp = rmanager.getNextRecord(addr, "index.catalog", index.recordSize);
		for (int i = 0; i < 50; i++){
			if (temp[i + 100])
				attrHasIndex += temp[i+100];
			if (temp[i])
				indexName += temp[i];
		}
		k = cmanager.isExistAttr(tableName, attrHasIndex)-1;//第几个属性有index
	}
	
	vector<char> newRecord;
	int recordSize = 0;
	for (int i = 0; i < type.size(); i++){
		if (type[i] == 1){//int
			intToChar4(atoi(value[i].c_str()), temp);
			recordSize += 4;
		}
		else if (type[i] == 2){//float
			floatToChar4(atof(value[i].c_str()), temp);
			recordSize += 4;
		}
		else{//char(n)
			temp.clear();
			int n = type[i] - 3;
			for (int j = 0; j < n; j++){
				if (j < value[i].size())//value[i]是string
					temp.push_back(value[i][j]);
				else
					temp.push_back(0);
			}
			recordSize += n;
		}
		newRecord.insert(newRecord.end(), temp.begin(), temp.end());
		if (i == k){
			valueForBtree = temp;
		}
	}

	for (int i = 0; i < 8; i++){
		newRecord.push_back(0);
	}
	recordSize += 8;

	Address returnAddr = rmanager.insertRecord(newRecord, tableName, recordSize);
	if (indexName != "")
		imanager.insert(indexName, valueForBtree, returnAddr);
	return 1;
}