//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "GlobalUnit.h"
#include "StyleItem.h"
#include "Compose.h"
#include "Project.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

/***************************************************************************************/
// 全局变量
/***************************************************************************************/
int					g_iMelodyKey = -1;		 					//主旋律调号
float				g_fMusicVolume = 1; 						//伴奏音量
bool				g_bComposeMute = false; 					//伴奏静音

TTheme				g_Theme;									//主旋律对象
TOpus				g_Opus;										//全曲对象
TOpusStageList&     g_lstOpusStages = g_Opus.StageList();		//曲式结构段落表

vector<UINT>		g_lstPaidStyleIDs;		//当前工程本次使用已支付风格ID列表

/***************************************************************************************/
// TCompose类函数
void TCompose::ClearStages()
{
	while( m_lstStages.size()>0 ){
		delete m_lstStages.back();
		m_lstStages.pop_back();
	}

	m_nBarCount = 0;
}

void TCompose::Clear()
{
	ClearStages();

	m_idLoc = m_idStyle = -1;
}

TOpusStage* TCompose::CopyStageAt( int iStage )
{
	if( iStage<0 || iStage>m_lstStages.size() )
		return NULL;

	TOpusStage *pSrcStage = m_lstStages[iStage],
			*pNewStage = new TOpusStage( pSrcStage );

	for( int j=0; j<pSrcStage->aBars.size(); j++ ){
		pNewStage->aBars.push_back( new TBar( pSrcStage->aBars[j] ));
	}

	for( int j=0; j<pSrcStage->aTracks.size(); j++ ){
		pNewStage->aTracks.push_back( new TTrack( pSrcStage->aTracks[j] ));
	}

	return pNewStage;
}

void TCompose::WriteProj( LOCSEGLIST& lstLocSeg, FILE* pFile )
{
	fwrite(&m_idLoc, sizeof(UINT), 1, pFile);
	fwrite(&m_idStyle, sizeof(UINT), 1, pFile);

	SaveOpusStages( m_lstStages, lstLocSeg, pFile );
}

int TCompose::ReadProj( STYLELIST& aUnsolvedStyles, FILE* pFile, DWORD dwVersion )
{
	fread(&m_idLoc, sizeof(UINT), 1, pFile);
	fread(&m_idStyle, sizeof(UINT), 1, pFile);

	int ret = LoadOpusStages( m_lstStages, aUnsolvedStyles, pFile, dwVersion );

	if( E_PROJ_FATALERROR>(DWORD)ret ){
		m_nBarCount = ret;
		ret = E_PROJ_NOERROR;
	}
	else{
		Clear();
	}

	return ret;
}

void TCompose::SetTempStyle( UINT idLoc, UINT idStyle, int idSet )
{
	if( m_idLoc==idLoc && m_idStyle==idStyle ){
		m_idLoc = -1;
		m_idStyle = idSet;
	}

	for( int s=0; s<m_lstStages.size(); s++ ){
		TOpusStage* pStage = m_lstStages[s];
		for( int t=0; t<pStage->aTracks.size(); t++ ){
			TTrack* pTrack = pStage->aTracks[t];
			if( pTrack->iStyleLoc==idLoc && pTrack->iStyleId==idStyle ){
				pTrack->iStyleLoc = -1;
				pTrack->iStyleId = idSet;
			}
		}
	}
}

void TCompose::Set( UINT idLoc, UINT idStyle, TOpusStageList& lstStages )
{
	ClearStages();

	m_idLoc = idLoc;
	m_idStyle = idStyle;

	for( int i=0; i<lstStages.size(); i++ ){
		TOpusStage *pSrcStage = lstStages[i],
				*pNewStage = new TOpusStage( pSrcStage );

		int nBars = pSrcStage->aBars.size();
		for( int j=0; j<nBars; j++ ){
			pNewStage->aBars.push_back( new TBar( pSrcStage->aBars[j] ));
		}

		m_nBarCount += nBars;

		for( int j=0; j<pSrcStage->aTracks.size(); j++ ){
			pNewStage->aTracks.push_back( new TTrack( pSrcStage->aTracks[j] ));
		}

		m_lstStages.push_back( pNewStage );
	}
}

void TCompose::Get( UINT& idLoc, UINT& idStyle, TOpusStageList& lstStages )
{
	idLoc = m_idLoc;
	idStyle = m_idStyle;

	for( int i=0; i<m_lstStages.size(); i++ ){
		lstStages.push_back( CopyStageAt(i) );
	}
}

void TCompose::GetSpecBanks( vector<BYTE>& lstBank )
{
	for( int s=0; s<m_lstStages.size(); s++ ){
		TOpusStage* pStage = m_lstStages[s];

		for( int t=0; t<pStage->aTracks.size(); t++ ){
			TTrack* pTrack = pStage->aTracks[t];

			if( pTrack->iBank!=0xFF ){
				bool bAdd = true;

				for( int b=0; b<lstBank.size(); b++ ){
					if( pTrack->iBank==lstBank[b] ){
						bAdd = false;
						break;
					}
				}

				if( bAdd )
					lstBank.push_back( pTrack->iBank );
			}
		}
	}
}

void TCompose::SetSpecBanks( BANKMAPLIST& lstMap )
{
	for( int s=0; s<m_lstStages.size(); s++ ){
		TOpusStage* pStage = m_lstStages[s];

		for( int t=0; t<pStage->aTracks.size(); t++ ){
			TTrack* pTrack = pStage->aTracks[t];

			if( pTrack->iBank!=0xFF ){
				for( int b=0; b<lstMap.size(); b++ ){
					TBankMap* pMap = lstMap[b];

					if( pTrack->iBank==pMap->iBankOld ){
						pTrack->iBank = pMap->iBankNew;
						break;
					}
				}
			}
		}
	}
}

/***************************************************************************************/
// TTheme类函数
TTheme::TTheme() : TCompose()
{
	m_bWeakup = false;
	m_iKey = -1;
}

void TTheme::Clear()
{
	TCompose::Clear();

	m_iKey = -1;
	m_bWeakup = false;
}

void TTheme::Set( UINT idLoc, UINT idStyle, TOpusStageList& lstStages )
{
	TCompose::Set( idLoc, idStyle, lstStages );

	m_iKey = g_iMelodyKey;
	if( lstStages.size()>0 ){
		TOpusStage* pSrcStage = m_lstStages[0];

		if( m_bWeakup && pSrcStage->aBars.size()>1 ){
			TOpusStage* pWeakStage = new TOpusStage( pSrcStage );

			pWeakStage->aBars.push_back( pSrcStage->aBars[0] );
			pSrcStage->aBars.erase( pSrcStage->aBars.begin() );

			for( int j=0; j<pSrcStage->aTracks.size(); j++ ){
				pWeakStage->aTracks.push_back( new TTrack( pSrcStage->aTracks[j] ));
			}

			m_lstStages.insert( m_lstStages.begin(), pWeakStage );
		}
	}
}

void TTheme::Set( TOpusStageList& lstStages )
{
	TCompose::Set( m_idLoc, m_idStyle, lstStages );
}

void TTheme::Build( TBarList& lstBars, vector<int>&lstStages )
{
	Clear();

	m_iKey = g_iMelodyKey;

	TStyleItem* pStyItem = g_pPreStyle;

	int nSegNum[4];
	vector<TSegmentItem*> aSegments[4];
	memset( nSegNum, 0, sizeof(int)*4 );

	if( pStyItem ){
		if( pStyItem->pStyle ){
			m_idLoc = pStyItem->pStyle->idLoc;
			m_idStyle = pStyItem->pStyle->idStyle;
		}
		else{
			m_idLoc = -1;
			m_idStyle = 0;
        }

		if( pStyItem->aItems->Count==0 ){
			TPROSTYLE* info = pStyItem->pStyle;

			for( int s=0; s<SEGTYPE_TRACK; s++ ){
				int rep = s<SEGTYPE_INTRO ? 1 : 2;
				for( int r=0; r<rep; r++ ){
					int numSeg = info->idLoc==0 ? info->pOrigin->detail.nSegNum[s]
										: info->idLoc==1 ? info->pShare->nSegNum[s]
														: info->pLocal->nSegNum[s];
					int num = s<SEGTYPE_INTRO ? numSeg
										: r==0 ? ( numSeg & 0x0F )
												: ( numSeg>>4 );

					if( num>0 ){
						DWORD opts = OPT_DEL | OPT_VOL | (s<SEGTYPE_INTRO ? OPT_BRUSH : 0);
						for( int i=0; i<num; i++ ){
							int sn = r==0 ? i : i+4;
							int vol = info->idLoc==0 ? 100
									: info->idLoc==1 ? info->pShare->nSegVol[s][sn]
													: info->pLocal->nSegVol[s][sn];
							TSegmentItem* pSegItem = pStyItem->AddSegment( s, sn, opts, 0, -1, vol, false );

							DWORD dwTrkOpt = OPT_DEL|OPT_FONTPROG|OPT_VOL;
							if( s<SEGTYPE_INTRO )
								dwTrkOpt |= OPT_TEXTURE;

							for( int j=0; j<16; j++ ){
								pSegItem->AddTrack( info, sn, j, dwTrkOpt, true );
							}

							if( pSegItem->aItems->Count>0 ){
								if( s==SEGTYPE_INTRO ){
									pSegItem->nBars = info->idLoc==0 ? info->pOrigin->detail.aIntroBars[sn]
													: info->idLoc==1 ? info->pShare->aIEBars[0][sn]
																	: info->pLocal->aIEBars[0][sn];
								}
								else if( s==SEGTYPE_ENDING ){
									pSegItem->nBars = info->idLoc==0 ? info->pOrigin->detail.aEndingBars[sn]
													: info->idLoc==1 ? info->pShare->aIEBars[1][sn]
																	: info->pLocal->aIEBars[1][sn];
								}

								aSegments[s].push_back( pSegItem );
								nSegNum[s]++;
							}
							else{
								pStyItem->DeleteSegment( pSegItem );
							}
						}
					}
				}
			}
		}
		else{
			for( int i=0; i<pStyItem->aItems->Count; i++ ){
				TSegmentItem* pSegment = (TSegmentItem*)pStyItem->aItems->Items[i];
				int stype = pSegment->GetSegType();
				aSegments[stype].push_back( pSegment );
				nSegNum[stype]++;
			}
		}
	}

	if( lstStages.size()>1 && lstStages[0]==0 )
		m_bWeakup = true;
	else
		m_bWeakup = false;

	int iSegNo = 0, iBar = 0;
	for( int i=0; i<lstStages.size(); i++ ){
		TOpusStage* pStage = new TOpusStage;
		pStage->iSegKey = g_iMelodyKey;
		pStage->iSegType = SEGTYPE_VAR;
		pStage->nVol = 100;
		pStage->iSegNo = -1;

		int nBar = lstStages[i] - iBar + 1;
		for( int j=0; j<nBar; j++ ){
			pStage->aBars.push_back( lstBars[iBar++] );
		}

		if( nSegNum[SEGTYPE_VAR]==0 ){
			delete pStage;
		}
		else{
			TSegmentItem* pSegment = aSegments[SEGTYPE_VAR][iSegNo];
			pStage->nVol = pSegment->volume;
			pStage->iSegNo = pSegment->iSegNo;

			ProduceTracks( pStage, pSegment );
			m_lstStages.push_back( pStage );
			m_nBarCount += nBar;

			if( nSegNum[SEGTYPE_FILL]>0 && nBar>1 && i<lstStages.size()-1 ){
				int iFill = iSegNo % nSegNum[SEGTYPE_FILL];
				TSegmentItem *pSegFill = aSegments[SEGTYPE_FILL][iFill];

				TOpusStage * pFillStage = new TOpusStage;
				pFillStage->iSegKey = g_iMelodyKey;
				pFillStage->iSegType = SEGTYPE_FILL;
				pFillStage->iSegNo = pSegFill->iSegNo;
				pFillStage->nVol = pSegFill->volume;

				pFillStage->aBars.push_back( pStage->aBars.back() );
				pStage->aBars.pop_back();

				ProduceTracks( pFillStage, pSegFill );
				m_lstStages.push_back( pFillStage );
			}

			if( iBar>1 && iSegNo < nSegNum[SEGTYPE_VAR]-1 )
				iSegNo = (iSegNo + 1) % nSegNum[SEGTYPE_VAR];
		}
	}
}

int TTheme::GetFirstChord()
{
	int iStage = m_bWeakup ? 1 : 0;

	return MAKELONG( m_lstStages[iStage]->aBars[0]->aChords.iType[0],
					m_lstStages[iStage]->aBars[0]->aChords.iKey[0] );
}

int TTheme::GetLastChord()
{
	return MAKELONG( m_lstStages.back()->aBars.back()->aChords.iType[g_nChordNumPerBar-1],
					m_lstStages.back()->aBars.back()->aChords.iKey[g_nChordNumPerBar-1] );
}

void TTheme::WriteProj( LOCSEGLIST& lstLocSeg, FILE* pFile )
{
	fwrite(&m_iKey, sizeof(int), 1, pFile);
	fwrite(&m_bWeakup, sizeof(bool), 1, pFile);

	TCompose::WriteProj( lstLocSeg, pFile );
}

int TTheme::ReadProj( STYLELIST& aUnsolvedStyles, FILE* pFile, DWORD dwVersion )
{
	fread(&m_iKey, sizeof(int), 1, pFile);
	fread(&m_bWeakup, sizeof(bool), 1, pFile);

	return TCompose::ReadProj( aUnsolvedStyles, pFile, dwVersion );
}

/***************************************************************************************/
// TOpus类函数
TOpus::TOpus()
{
	m_bModified = false;
	m_iKeyBk = -1;
}

TOpus::~TOpus()
{
	ClearBackup();
}

void TOpus::ClearBackup()
{
	m_bModified = false;
	m_iKeyBk = -1;

	while( m_lstStagesBk.size()>0 ){
		delete m_lstStagesBk.back();
		m_lstStagesBk.pop_back();
	}
}

void TOpus::Clear()
{
	TCompose::Clear();

	ClearBackup();
	m_aStageBars.clear();
}

void TOpus::Set( UINT idLoc, UINT idStyle, TOpusStageList& lstStages )
{
	TCompose::Set( idLoc, idStyle, lstStages );

	CountBars();
}

void TOpus::WriteProj( LOCSEGLIST& lstLocSeg, FILE* pFile )
{
	m_idLoc = (g_pUseStyle && g_pUseStyle->pStyle) ? g_pUseStyle->pStyle->idLoc : 0;
	m_idStyle = (g_pUseStyle && g_pUseStyle->pStyle) ? g_pUseStyle->pStyle->idStyle : 0;

	TCompose::WriteProj( lstLocSeg, pFile );
}

int TOpus::ReadProj( STYLELIST& aUnsolvedStyles, FILE* pFile, DWORD dwVersion )
{
	int ret = TCompose::ReadProj( aUnsolvedStyles, pFile, dwVersion );

	if( ret==E_PROJ_NOERROR ){
		CountBars();
	}

	return ret;
}

void TOpus::Backup()
{
	ClearBackup();

	m_iKeyBk = g_iMelodyKey;

	for( int i=0; i<m_lstStages.size(); i++ ){
		TOpusStage *pNewStage = new TOpusStage;
		TOpusStage *pBkStage = m_lstStages[i];

		pNewStage->iSegKey = pBkStage->iSegKey;
		pNewStage->iSegType = pBkStage->iSegType;
		pNewStage->iSegNo = pBkStage->iSegNo;
		pNewStage->nVol = pBkStage->nVol;

		for( int j=0; j<pBkStage->aBars.size(); j++ ){
			TBar* pBar = new TBar;
			pBar->iBarKey = pBkStage->aBars[j]->iBarKey;
			memcpy( &pBar->aChords,
						&pBkStage->aBars[j]->aChords,
						sizeof(TBarChords) );
			pNewStage->aBars.push_back( pBar );
		}

		for( int j=0; j<pBkStage->aTracks.size(); j++ ){
			TTrack * pTrack = new TTrack;
			memcpy( pTrack, pBkStage->aTracks[j], sizeof(TTrack) );

			pNewStage->aTracks.push_back( pTrack );
		}

		m_lstStagesBk.push_back( pNewStage );
	}

	m_bModified = false;
}

BOOL TOpus::CheckModified( int iCheckType )
{
	if( iCheckType==CHECK_GET ){
		return m_bModified;
	}

	m_bModified &= ~iCheckType;

	if( iCheckType & CHECK_KEY ){
		if( m_iKeyBk!=g_iMelodyKey ){
			m_bModified |= CHECK_KEY;
		}
	}

	if( !(m_bModified & CHECK_KEY) && ( iCheckType & CHECK_STAGE) ){
		if( m_lstStagesBk.size()!=m_lstStages.size() ){
			m_bModified |= CHECK_STAGE;
		}
	}

	if( !(m_bModified & CHECK_STAGE) && (iCheckType & CHECK_STAGE || iCheckType & CHECK_TRACK
															|| iCheckType & CHECK_CHORD )){
		for( int i=0; i<m_lstStagesBk.size(); i++ ){
			TOpusStage* pOpStage = m_lstStages[i];
			TOpusStage* pBkStage = m_lstStagesBk[i];

			if( !(m_bModified & CHECK_STAGE) && (iCheckType & CHECK_STAGE)
						|| !(m_bModified & CHECK_CHORD) && iCheckType & CHECK_CHORD ){
				if( pOpStage->aBars.size()!=pBkStage->aBars.size()
						|| pOpStage->iSegType!=pBkStage->iSegType
						|| pOpStage->nVol!=pBkStage->nVol
						|| pOpStage->iSegKey!=pBkStage->iSegKey ){
					m_bModified |= CHECK_STAGE;
				}
				else if(iCheckType & CHECK_CHORD && pBkStage->iSegType<=SEGTYPE_FILL ){
					for( int j=0; j<pBkStage->aBars.size(); j++ ){
						TBarChords* pOpBar = &pOpStage->aBars[j]->aChords;
						TBarChords* pBkBar = &pBkStage->aBars[j]->aChords;

						if( memcmp( pOpBar, pBkBar, sizeof(TBarChords ))){
							m_bModified |= CHECK_CHORD;
							break;
						}
					}
				}
			}

			if( !(m_bModified & CHECK_TRACK) && (iCheckType & CHECK_TRACK) ){
				if( pOpStage->aTracks.size()!=pBkStage->aTracks.size() ){
					m_bModified |= CHECK_TRACK;
				}
				else{
					for( int j=0; j<pBkStage->aTracks.size(); j++ ){
						TTrack* pOpTrack = pOpStage->aTracks[j];
						TTrack* pBkTrack = pBkStage->aTracks[j];

						if( pOpTrack->iStyleId!=pBkTrack->iStyleId
									|| pOpTrack->iStyleLoc!=pBkTrack->iStyleLoc
									|| pOpTrack->iSegNo!=pBkTrack->iSegNo
									|| pOpTrack->iChanNo!=pBkTrack->iChanNo
									|| pOpTrack->iFile!=pBkTrack->iFile
									|| pOpTrack->iBank!=pBkTrack->iBank
									|| pOpTrack->iChanSpec!=pBkTrack->iChanSpec ){
							m_bModified |= CHECK_TRACK;
							break;
						}

						if( (iCheckType & CHECK_PROG) && pOpTrack->iProg!=pBkTrack->iProg ){
							m_bModified |= CHECK_PROG;
							break;
						}

						if( (iCheckType & CHECK_VOL) && pOpTrack->nVol!=pBkTrack->nVol ){
							m_bModified |= CHECK_VOL;
							break;
						}
					}
				}
			}
		}
	}

	return m_bModified;
}

void TOpus::BuildStyleItem()
{
	if( m_lstStages.empty() ){
		g_pUseStyle = NULL;
		return;
	}

	TPROSTYLE* info = GetStyleInfo( m_idLoc, m_idStyle );
	TStyleItem* pSty = new TStyleItem( info, 0 );

	for( int i=0; i<m_lstStages.size(); i++ ){
		TOpusStage* pStage = m_lstStages[i];

		int ind = 0;
		DWORD opts = OPT_DEL|OPT_VOL;
		if( pStage->iSegType<=SEGTYPE_FILL ){
			ind = pSty->nSegNum[0] + pSty->nSegNum[1];
			opts |= OPT_BRUSH;
		}
		else
			ind = pSty->nSegNum[pStage->iSegType];

		TSegmentItem* pSegItem = pSty->AddSegment( pStage->iSegType,
														pStage->iSegNo,
														opts,
														pStage->aBars.size(),
														ind,
														pStage->nVol,
														false );

		opts = OPT_DEL|OPT_FONTPROG|OPT_VOL;
		if( pStage->iSegType<=SEGTYPE_FILL )
			opts |= OPT_TEXTURE;
		for( int j=0; j<pStage->aTracks.size(); j++ ){
			TTrack* pTrack = pStage->aTracks[j];

			int idLoc = pTrack->iStyleLoc,
				idStyle = pTrack->iStyleId;
			TPROSTYLE* pStyle = GetStyleInfo( idLoc, idStyle );

			if( !pStyle ){
				DebugPrint( "风格文件已失效！\n" );

				delete pTrack;
				pStage->aTracks.erase( pStage->aTracks.begin() + j );
				j--;

				continue;
			}

			pSegItem->AddTrack( pStyle, pTrack, opts, false );

			if( !info ){
				pSty->pStyle = pStyle;
			}
		}
	}

	g_pUseStyle = pSty;
}

void TOpus::CopyStages( int iStartBar, int iEndBar, TOpusStageList* lstStages )
{
	int iBar = iStartBar;
	int iFirstBar, iSrcStage = FindStage( iBar, &iFirstBar );

	while( iBar<=iEndBar ){
		int nOffsetBar = iBar-iFirstBar;
		TOpusStage* pOriStage = m_lstStages[iSrcStage];
		int nCopyBar = pOriStage->aBars.size() - nOffsetBar;

		if( nCopyBar>iEndBar-iBar+1 )
			nCopyBar = iEndBar-iBar+1;

		TOpusStage* pNewStage = new TOpusStage( pOriStage );

		int iCopyEndBar = nOffsetBar + nCopyBar;
		for( int i=nOffsetBar; i<iCopyEndBar; i++ ){
			pNewStage->aBars.push_back( new TBar( pOriStage->aBars[i] ) );
		}

		for( int j=0; j<pOriStage->aTracks.size(); j++ ){
			pNewStage->aTracks.push_back( new TTrack( pOriStage->aTracks[j] ));
		}

		lstStages->push_back( pNewStage );

		iBar += nCopyBar;
		iSrcStage++;
		iFirstBar = iBar;
	}
}

void TOpus::ChangeKey( int iBarStart, int iBarEnd, int iKey, int keys[] )
{
	if( iBarStart<0 )
		iBarStart = 0;
	if( iBarEnd<0 )
		iBarEnd = m_nBarCount - 1;

	int iBar = iBarStart,
		iFirstKey = -1;
	while( iBar<=iBarEnd ){
		int iFirstBar, iStage = FindStage( iBar, &iFirstBar );
		TOpusStage* pStage = m_lstStages[iStage];

		int iSetKey = keys!=NULL ? keys[iBar-iBarStart] : iKey;

		if( iFirstKey<0 )
			iFirstKey = iSetKey;

		if( pStage->iSegType>=SEGTYPE_INTRO && iBar==iFirstBar ){
			pStage->iSegKey = iSetKey;
			iBar += pStage->aBars.size();
		}
		else{
			int iStart = max( iBar, iFirstBar ),
				iEnd = min( iBarEnd, (int)(iFirstBar + pStage->aBars.size() - 1) );

			for( int i = iStart; i<=iEnd; i++ ){
				TBar *pBar = pStage->aBars[i-iFirstBar];

				int iDiff = iSetKey - pBar->iBarKey;
				pBar->iBarKey = iSetKey;

				for( int k=0; k<4; k++ ){
					pBar->aChords.iKey[k] += iDiff;
					if( pBar->aChords.iKey[k]>0x7F )
						pBar->aChords.iKey[k] += KEY_NUM;
					else if( pBar->aChords.iKey[k]>=KEY_NUM )
						pBar->aChords.iKey[k] -= KEY_NUM;
				}
			}

			iBar = iEnd + 1;
		}
	}
}

void TOpus::InsertStage( int iIns, TOpusStage* pStage )
{
	int nBar = pStage->aBars.size();

	if( iIns<0 || iIns>=StageCount() ){
		m_lstStages.push_back( pStage );

		int iBegin = m_nBarCount,
			iEnd = iBegin + nBar - 1;

		m_aStageBars.push_back( MAKELONG( iBegin, iEnd ) );

		m_nBarCount += nBar;
	}
	else{
		m_lstStages.insert( m_lstStages.begin()+iIns, pStage );

		int	iBegin = iIns==0 ? 0 : HIWORD(m_aStageBars[iIns-1]) + 1,
			iEnd = iBegin + nBar - 1;

		m_aStageBars.insert( m_aStageBars.begin()+iIns, MAKELONG( iBegin, iEnd ) );

		for( int i=iIns+1; i<m_aStageBars.size(); i++ ){
			iBegin = LOWORD(m_aStageBars[i]) + nBar;
			iEnd = HIWORD(m_aStageBars[i]) + nBar;

			m_aStageBars[i] = MAKELONG( iBegin, iEnd );
		}

		m_nBarCount += nBar;
	}
}

void TOpus::RemoveStage( int iDel )
{
	TOpusStage* pStage = m_lstStages[iDel];

	int nBar = pStage->aBars.size();

	delete pStage;
	m_lstStages.erase( m_lstStages.begin() + iDel );
	m_aStageBars.erase( m_aStageBars.begin() + iDel );

	if( nBar>0 ){
		for( int i=iDel; i<m_aStageBars.size(); i++ ){
			int iBegin = LOWORD(m_aStageBars[i]) - nBar,
				iEnd = HIWORD(m_aStageBars[i]) - nBar;

			m_aStageBars[i] = MAKELONG( iBegin, iEnd );
		}

		m_nBarCount -= nBar;
	}
}

void TOpus::CutStage( int iStage, int iCutBar )
{
	int iFirstBar = LOWORD(m_aStageBars[iStage]),
		iEndBar = HIWORD(m_aStageBars[iStage]);

	if( iCutBar<=iFirstBar || iCutBar>iEndBar )
		return;

	TOpusStage* pOriStage = g_lstOpusStages[iStage];
	TOpusStage* pCutStage = new TOpusStage;

	pCutStage->iSegKey = pOriStage->iSegKey;
	pCutStage->iSegNo = pOriStage->iSegNo;
	pCutStage->iSegType = pOriStage->iSegType;
	pCutStage->nVol = pOriStage->nVol;

	for( int i=0; i<pOriStage->aTracks.size(); i++ ){
		TTrack * pTrack = new TTrack( pOriStage->aTracks[i] );

		pCutStage->aTracks.push_back( pTrack );
	}

	int nBarNum = pOriStage->aBars.size()-(iCutBar-iFirstBar);

	for( int i=0; i<nBarNum; i++ ){
		pCutStage->aBars.insert( pCutStage->aBars.begin(), pOriStage->aBars.back() );
		pOriStage->aBars.pop_back();
	}

	m_lstStages.insert( m_lstStages.begin()+iStage+1, pCutStage );
	m_aStageBars[iStage] = MAKELONG( iFirstBar, iCutBar-1 );
	m_aStageBars.insert( m_aStageBars.begin()+iStage+1, MAKELONG(iCutBar, iEndBar) );
}

void TOpus::ChangeStageBar( int iStage, int nBar, bool bCount )
{
	int iFirstBar = LOWORD(m_aStageBars[iStage]),
		iEndBar = HIWORD(m_aStageBars[iStage]) + nBar;

	m_aStageBars[iStage] = MAKELONG( iFirstBar, iEndBar );

	if( bCount ){
		for( int i=iStage+1; i<m_aStageBars.size(); i++ ){
			int iBegin = LOWORD(m_aStageBars[i]) + nBar,
				iEnd = HIWORD(m_aStageBars[i]) + nBar;

			m_aStageBars[i] = MAKELONG( iBegin, iEnd );
		}

		m_nBarCount += nBar;
	}
}

void TOpus::CountBars()
{
	m_aStageBars.clear();
	m_nBarCount = 0;

	int iBegin = 0, iEnd = -1;
	for( int i=0; i<m_lstStages.size(); i++ ){
		TOpusStage* pStage = m_lstStages[i];

		m_nBarCount += pStage->aBars.size();
		iBegin = iEnd + 1;
		iEnd += pStage->aBars.size();

		m_aStageBars.push_back( MAKELONG( iBegin, iEnd ) );
	}
}

int TOpus::FindStage( int iBar, int *piFirstBar )
{
	if( iBar>=0 && iBar<m_nBarCount ){
		for( int i=0; i<m_aStageBars.size(); i++ ){
			int iSBegin = LOWORD(m_aStageBars[i]);
			int iSEnd = HIWORD(m_aStageBars[i]);

			if( iBar>=iSBegin && iBar<=iSEnd ){
				if( piFirstBar )
					*piFirstBar = iSBegin;

					return i;
			}
		}
	}

	return -1;
}

int TOpus::StageFirstBar( int iStage )
{
	if( iStage>=0 && iStage<m_aStageBars.size() ){
		return LOWORD(m_aStageBars[iStage]);
	}

	return -1;
}

int TOpus::StageLastBar( int iStage )
{
	if( iStage>=0 && iStage<m_aStageBars.size() ){
		return HIWORD(m_aStageBars[iStage]);
	}

	return -1;
}

DWORD TOpus::StageRange( int iStage )
{
	if( iStage>=0 && iStage<m_aStageBars.size() ){
		return m_aStageBars[iStage];
	}

	return -1;
}

/***************************************************************************************/
// 全局函数
/***************************************************************************************/
int FindStage( int iBar, int *piFirstBar )
{
	return g_Opus.FindStage( iBar, piFirstBar );
/*	if( iBar>=0 && iBar<g_Opus.BarCount() ){
		int nStageNum = g_lstOpusStages.size();
		int nBarCount = 0;
		for( int i=0; i<nStageNum; i++ ){
			TOpusStage* pStage = g_lstOpusStages[i];

			if( piFirstBar )
				*piFirstBar = nBarCount;

			nBarCount += pStage->aBars.size();

			if( iBar<nBarCount ){
				return i;
			}
		}
	}

	return -1;
*/
}

int FirstBar( int iStage )
{
	return g_Opus.StageFirstBar( iStage );
/*	if( iStage<0 || iStage>=g_lstOpusStages.size() )
		return -1;

	int nBarCount = 0;
	for( int i=0; i<iStage; i++ ){
		TOpusStage* pStage = g_lstOpusStages[i];

		nBarCount += pStage->aBars.size();
	}

	return nBarCount;
*/
}

int GetBarCount()
{
	return g_Opus.BarCount();
/*	int nBarCount = 0;
	for( int i=0; i<g_lstOpusStages.size(); i++ ){
		TOpusStage* pStage = g_lstOpusStages[i];

		nBarCount += pStage->aBars.size();
	}

	return nBarCount;
*/
}

int GetBarKey( int iBar )
{
	int iFirstBar, iStage = FindStage( iBar, &iFirstBar );

	if( iStage<0 )
		return -1;

	if( g_lstOpusStages[iStage]->iSegType>=SEGTYPE_INTRO )
		return g_lstOpusStages[iStage]->iSegKey;
	else
		return g_lstOpusStages[iStage]->aBars[iBar-iFirstBar]->iBarKey;
}

TOpusStage* DuplicateStage( TOpusStage* pSrc )
{
	TOpusStage* pNew = new TOpusStage( pSrc );

	for( int j=0; j<pSrc->aBars.size(); j++ ){
		pNew->aBars.push_back( new TBar( pSrc->aBars[j] ));
	}

	for( int j=0; j<pSrc->aTracks.size(); j++ ){
		pNew->aTracks.push_back( new TTrack( pSrc->aTracks[j] ));
	}

	return pNew;
}

void ProduceTracks( TOpusStage* pStage, void* pSegItem )
{
	TSegmentItem* pSeg = (TSegmentItem*)pSegItem;

	for( int i=0; i<pSeg->aItems->Count; i++ ){
		TTrackItem* pTrk = (TTrackItem*)pSeg->aItems->Items[i];

		TTrack * pTrack = new TTrack( pTrk->pTrack );
		pStage->aTracks.push_back( pTrack );
	}
}

bool DiffStages( TOpusStage* pStage1, TOpusStage* pStage2, bool bPassSegNo,
															bool bPassFile )
{
	bool bDiff = true;

	if( pStage1->iSegType==pStage2->iSegType
					&& pStage1->iSegKey==pStage2->iSegKey
					&& pStage1->nVol==pStage2->nVol
					&& ( bPassSegNo || pStage1->iSegNo==pStage2->iSegNo )
					&& pStage1->aTracks.size()==pStage2->aTracks.size() ){
		bDiff = false;

		if( !pStage1->aTracks.empty() ){
			int num = pStage1->aTracks.size();
			bool* aMatch = new bool[num];
			memset( aMatch, false, sizeof(bool)*num );

			for( int i=0; i<num; i++ ){
				TTrack* pTrk1 = pStage1->aTracks[i];

				bool bFound = false;
				for( int j=0; j<num; j++ ){
					TTrack* pTrk2 = pStage2->aTracks[j];
					if( !aMatch[j] && pTrk1->iStyleId==pTrk2->iStyleId
								&& pTrk1->iStyleLoc==pTrk2->iStyleLoc
								&& pTrk1->iSegNo==pTrk2->iSegNo
								&& pTrk1->iChanNo==pTrk2->iChanNo
								&& pTrk1->iBank==pTrk2->iBank
								&& pTrk1->iProg==pTrk2->iProg
								&& pTrk1->nVol==pTrk2->nVol
								&& ( bPassFile || pTrk1->iFile==pTrk2->iFile
												|| pTrk1->iFile==0xFF
												|| pTrk2->iFile==0xFF )){
						bFound = true;
						aMatch[j] = true;

						break;
					}
				}

				if( !bFound ){
					bDiff = true;
					break;
				}
			}

			delete[] aMatch;
		}
	}

	return bDiff;
}

