//-----------------------
// Storm.cpp 
// Copyleft by Yuki Kamino

#include "stdafx.h"
#include "Storm.h"

#define MAX_LOADSTRING 100

// グローバル変数:
HINSTANCE hInst;                                                                        // 現在のインターフェイス
TCHAR szTitle[MAX_LOADSTRING];                                  // タイトル バーのテキスト
TCHAR szWindowClass[MAX_LOADSTRING];                    // メイン ウィンドウ クラス名
HWND hMainWnd;
TCHAR *srcArasi, *srcOld;
TCHAR *topBuf;
int lineNo;
TCHAR strErrMsg[256];
TCHAR nameIn[128];
TCHAR *textIn;
TCHAR *strIn;
int nVal;
double dVal;
int lenInt;
unsigned int uVal;
int backedToken;
Set *topSet, *curSet;
int crtXRes, crtYRes;
int prnXRes, prnYRes;
int curMeasUnit = MU_MM;
double measFactor = 1;
double curPoint = 10;
Ara *pAra;
int numAra, maxAra;
double defFontSize = 10;
double defCellWid = 12;
int topOffset;
int codePos;
DataSet *pDataSetTop;
int insRec;
int evalRec;
DataSet *pDStd;
int recStd;
int posStd;
Set *pSetOn;
BOOL bNoInplace;
DataSet *curData;
Parts *partsTop;
Parts *partsArr[1024];
int partsNum;
int partsAt;
TCHAR *strHyper;
COLORREF colParts;
int widParts;
HPEN hPenRed;
Mic *micTop;
RECT rcp;
BOOL bCodeMode;
LOGFONT lfSelect2;
int sizeSelect2 = 10;
int startTime;
Creature *topCreature, *curCreature;
OnClick *topOnClick, *curOnClick;
Cell *cellAt;
int cellX, cellY;
COLORREF colValue;
For *curFor;
Hyper *curHyper;
PARA *pHyper;
int numHyper, maxHyper;
Ara *curHyperAra;


BOOL ParseE();  // for RDP

ATOM                            MyRegisterClass(HINSTANCE hInstance);
BOOL                            InitInstance(HINSTANCE, int);
LRESULT CALLBACK        WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK        About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
        UNREFERENCED_PARAMETER(hPrevInstance);

  BOOL bOpen = FALSE;
  if (lpCmdLine && *lpCmdLine)
  {
    BOOL bQt = FALSE;
    if (*lpCmdLine == '"')
      bQt = TRUE;
    lstrcpy(AppFile, bQt ? lpCmdLine + 1 : lpCmdLine);
    if (bQt)
    {
      int len = lstrlen(AppFile);
      if (len > 1 && AppFile[len - 1] == '"')
        AppFile[len - 1] = 0;
    }
    bOpen = TRUE;
  }

  if (CheckKeywordOrder())
    return 0;

  MSG msg;
        HACCEL hAccelTable;

  topSet = new Set;                      // ゴミ捨ては最後に
  ZeroMemory(topSet, sizeof(Set));
  curSet = topSet;
  GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lfSelect2);
  lstrcpy(lfSelect2.lfFaceName, _T("MS 明朝"));


        // グローバル文字列を初期化しています。
        LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadString(hInstance, IDC_STORM, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);

        // アプリケーションの初期化を実行します:
        if (!InitInstance (hInstance, nCmdShow))
        {
                return FALSE;
        }

        hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_STORM));

  if (bOpen)
  {
    DoOpenA();
  }

        // メイン メッセージ ループ:
        while (GetMessage(&msg, NULL, 0, 0))
        {
                if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
                {
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                }
        }

        return (int) msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
        WNDCLASSEX wcex;

        wcex.cbSize = sizeof(WNDCLASSEX);

        wcex.style                      = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc        = WndProc;
        wcex.cbClsExtra         = 0;
        wcex.cbWndExtra         = 0;
        wcex.hInstance          = hInstance;
        wcex.hIcon                      = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_STORM));
        wcex.hCursor            = NULL; //LoadCursor(NULL, IDC_ARROW);  // ちらつき防止のため
        wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName       = MAKEINTRESOURCE(IDC_STORM);
        wcex.lpszClassName      = szWindowClass;
        wcex.hIconSm            = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

        return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // グローバル変数にインスタンス処理を格納します。

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
     10, 10,950, 700,
     // CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
      NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   hMainWnd = hWnd;

   SetTimer(hWnd, 1, 100, NULL);
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   startTime = GetTickCount();

   return TRUE;
}

void OnCreate(HWND hWnd)
{
  HDC hDC = GetDC(hWnd);
  crtXRes = GetDeviceCaps(hDC, LOGPIXELSX);  // dots per inch
  crtYRes = GetDeviceCaps(hDC, LOGPIXELSY);

  HMENU hMenu = GetMenu(hWnd);
  EnableMenuItem(hMenu, IDM_OPEN_D, MF_GRAYED);
  EnableMenuItem(hMenu, IDM_SAVE_D, MF_GRAYED);
  EnableMenuItem(hMenu, IDM_SAVEAS_D, MF_GRAYED);

  ReleaseDC(hWnd, hDC);

  hPenRed = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
}

void GoLink(HWND hWnd, int diff)
{
  int n = GetDataInt(pDStd, insRec, posStd);
  DataSet *pLink = pDStd->item[posStd].link;
  int at = FindIDData(pLink, n);
  int at2 = at;
  if (diff < 0)
  {
    if (at > 0)
      at2--;
    else
      at2 = pLink->RecNum - 1;
  }
  else if (diff > 0)
  {
    if (at < pLink->RecNum -1)
      at2++;
    else
      at2 = 0;
  }
  if (at != at2)
  {
    int m = GetDataInt(pLink, at2, pLink->posID);
    SetDataInt(pDStd, insRec, posStd, m);
    Renew();
    InvalidateRect(hWnd, NULL, TRUE);
  }
}

void OnWheel(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  int dx = (short)HIWORD(wParam);
  int diff = -dx/120;
  if (diff == 0)
    return;
  if (pDStd && insRec >= 0 && posStd >= 0 && posStd < pDStd->num)
  {
    if (pDStd->item[posStd].type == FT_LINK)
    {
      GoLink(hWnd, diff);
    }
    else if (pDStd->item[posStd].type == FT_INT)
    {
      int n = GetDataInt(pDStd, insRec, posStd);
      n += diff;
      SetDataInt(pDStd, insRec, posStd, n);
      Renew();
      InvalidateRect(hWnd, NULL, TRUE);
    }
    else if (pDStd->item[posStd].type == FT_DBL)
    {
      double x = GetDataDbl(pDStd, insRec, posStd);
      x += diff;
      SetDataDbl(pDStd, insRec, posStd, x);
      Renew();
      InvalidateRect(hWnd, NULL, TRUE);
    }
  }
}

CBTYPE ProcEdit;
TCHAR strOn[256];
HWND hEdit;
Variable *pVarAt, *pVarOn;
int xx0, xx1, yy0, yy1;
HFONT hEditFont;

void EndInplace(HWND hWnd, BOOL bOK)
{
  if (bOK)
  {
    GetWindowText(hEdit, strOn, 250);
    if (pVarOn)
    {
      TCHAR *pp;
      switch (pVarOn->type)
      {
      case VT_INT:
        pVarOn->nVal = _tcstol(strOn, &pp, 10);
        break;
      case VT_DBL:
        pVarOn->dVal = _tcstod(strOn, &pp);
        break;
      case VT_STR:
        if (pVarOn->str)
          delete [] pVarOn->str;
        pVarOn->str = new TCHAR[lstrlen(strOn) + 1];
        lstrcpy(pVarOn->str, strOn);
        break;
      }
    }
    else if (pDStd && posStd >= 0)
    {
      int type = pDStd->item[posStd].type;
      TCHAR *pp;
      switch (type)
      {
      case FT_STR:
        SetDataStr(pDStd, insRec, posStd, strOn);
        break;
      case FT_INT:
        SetDataInt(pDStd, insRec, posStd, _tcstol(strOn, &pp, 10));
        break;
      case FT_DBL:
        SetDataDbl(pDStd, insRec, posStd, _tcstod(strOn, &pp));
        break;
      }
    }
    else
      SetWindowText(hMainWnd, posStd < 0 ? _T("MMM") : (pDStd == NULL ? _T("NULL") : strOn)); /////////////////
  }
  pDStd = NULL;
  pVarOn = NULL;
  if (hEdit)
    DestroyWindow(hEdit);
  hEdit = NULL;
  if (hEditFont)
    DeleteObject(hEditFont);
  hEditFont = NULL;
  Renew();
  InvalidateRect(hMainWnd, NULL, TRUE);
}

LRESULT CALLBACK EditHook(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam)
{
  if (mes == WM_KEYDOWN)
  {
    if (wParam == VK_RETURN || wParam == VK_ESCAPE)
    {
      EndInplace(hWnd, wParam == VK_RETURN);
    }
  }
  return CallWindowProc(ProcEdit, hWnd, mes, wParam, lParam);
}

void BeginInplace(HWND hWnd)
{
  hEditFont = GetDefFont(FALSE);
  int hh = PixY(defFontSize*0.15, FALSE, FALSE);
  BOOL bLink = FALSE;
  int dd = bLink ? hh/10 : hh/5;
  hEdit = CreateWindow(_T("edit"), strOn, WS_CHILD | ES_AUTOHSCROLL,
          xx0+dd, yy0+dd, xx1-dd, yy1-dd, hWnd, (HMENU)512, NULL, NULL);
  ProcEdit = (CBTYPE)SetWindowLong(hEdit, GWL_WNDPROC, (LPARAM)EditHook);
  if (hEditFont)
    SendMessage(hEdit, WM_SETFONT, (WPARAM)hEditFont, 0);
  SetFocus(hEdit);
  SendMessage(hEdit, EM_SETSEL, 0, -1);
  ShowWindow(hEdit, SW_SHOW);
}

void DoColor()
{
  CHOOSECOLOR cc;
  static COLORREF cr[32];
  ZeroMemory(&cc, sizeof(cc));
  cc.lStructSize = sizeof(cc);
  cc.hwndOwner = hMainWnd;
  cc.hInstance = NULL;
  cc.rgbResult = RGB(0, 0, 0);
  cc.lpCustColors = cr;
  cc.Flags = CC_ANYCOLOR | CC_RGBINIT | CC_FULLOPEN;
  if (ChooseColor(&cc))
  {
    unsigned u = cc.rgbResult;
    int b = (u & 0xFF0000) >> 16;
    int g = (u & 0xFF00) >> 8;
    int r = u & 0xFF;
    colParts = RGB(r, g, b);
    InvalidateRect(hMainWnd, NULL, TRUE);
  }
}

void DoHyper(TCHAR *str, BOOL bR = FALSE)
{
  SetWindowText(hMainWnd, str); //////////////
}

void OnRButtonUp(HWND hWnd, int x, int y)
{
  ReleaseCapture();
  if (topSet->next != curSet)
  {
    if (strHyper)
    {
      DoHyper(strHyper, TRUE);
      return;
    }
  }
  if (hEdit)
  {
    EndInplace(hWnd, TRUE);
    return;
  }
  else if (pDStd)
  {
    int type = pDStd->item[posStd].type;
    if (type == FT_LINK)
    {
      GoLink(hWnd, -1);
    }
  }
}

COLORREF colText;

void ColorBox2(HWND hDlg)
{
  CHOOSECOLOR cc;
  static COLORREF cr[32];
  ZeroMemory(&cc, sizeof(cc));
  cc.lStructSize = sizeof(cc);
  cc.hwndOwner = hDlg;
  cc.hInstance = NULL;
  cc.rgbResult = RGB(0, 0, 0);
  cc.lpCustColors = cr;
  cc.Flags = CC_ANYCOLOR | CC_RGBINIT | CC_FULLOPEN;
  if (ChooseColor(&cc))
  {
    unsigned u = cc.rgbResult;
    int b = (u & 0xFF0000) >> 16;
    int g = (u & 0xFF00) >> 8;
    int r = u & 0xFF;

    colText = RGB(r, g, b);
  }
}


void FontBox2(HWND hDlg)
{
  GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lfSelect2);
  lstrcpy(lfSelect2.lfFaceName, _T("MS ゴシック"));
  lfSelect2.lfHeight = int(crtYRes*sizeSelect2/72);
  lfSelect2.lfWidth = 0;
  CHOOSEFONT cf;
  ZeroMemory(&cf, sizeof(cf));
  cf.lStructSize = sizeof(cf);
  cf.hwndOwner = hDlg;
  cf.hDC = NULL;
  cf.lpLogFont = &lfSelect2;
  cf.Flags = CF_INITTOLOGFONTSTRUCT;

  if (ChooseFont(&cf))
  {
    sizeSelect2 = cf.iPointSize/10;
  }
}

TCHAR *strText;

INT_PTR CALLBACK EditText(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
        UNREFERENCED_PARAMETER(lParam);
  int n = LOWORD(wParam);
        switch (message)
        {
        case WM_INITDIALOG:
    if (srcArasi && *srcArasi)
    {
      SetWindowText(GetDlgItem(hDlg, IDC_SRC), srcArasi + 1); // 先頭はBOM
    }
    SetFocus(GetDlgItem(hDlg, IDC_SRC));
                return (INT_PTR)TRUE;

        case WM_COMMAND:
    switch (n)
    {
    case IDOK:
      {
        if (strText)
          delete [] strText;
        int len = GetWindowTextLength(GetDlgItem(hDlg, IDC_SRC));
        strText = new TCHAR[len + 1];
        GetDlgItemText(hDlg, IDC_SRC, strText, len + 1);
      }
      // no break
    case IDCANCEL:
                        EndDialog(hDlg, LOWORD(wParam));
                        return (INT_PTR)TRUE;
    case IDC_FONT:
      FontBox2(hDlg);
      return (INT_PTR)TRUE;
    case IDC_COLOR:
      ColorBox2(hDlg);
      return (INT_PTR)TRUE;
    default:
      break;
    }
                break;
        }
        return (INT_PTR)FALSE;
}

void AddText(Text *p)
{
  if (curSet->textTop)
  {
    Text *q;
    for (q = curSet->textTop; q->next; q = q->next)
      ;
    q->next = p;
  }
  else
    curSet->textTop = p;
}

void OnClickCreature(OnClick *p)
{
  p->span = 10;  ////////////////////////////////////////
  p->start = GetTickCount();
  p->goal = p->start + p->span*1000 + 999;
  p->time = p->span + 1;
  OnTimerClick(hMainWnd);
}

void FlipCross(Cell *p, int x, int y)
{
  DataSet *pD = p->pD;
  CrossItem *pC = p->pCrossItem;
  Path *pX = pC->pX;
  Path *pY = pC->pY;
  Path *pV = pC->pV;
  int nx = PathWid(pX);
  int ny = PathWid(pY);
  int n = 0;
  BOOL bDbl = FALSE;
  double dx = 0;
  int xx = 0;
  int type = pV ? GetPathType(pV) : FT_INT;
  for (int i = 0; i < pD->RecNum; i++)
  {
    if (x < nx)
    {
      int rec = GetTermRec(pX, i);
      if (rec != x)
        continue;
    }
    if (y < ny)
    {
      int rec = GetTermRec(pY, i);
      if (rec != y)
        continue;
    }
    if (pV)
    {
      int rec = GetTermRec(pV, i);
      if (type == FT_DBL)
      {
        dx += GetPathDbl(pV, rec);
      }
      else
      {
        xx += GetPathInt(pV, rec);
      }
    }
    else
      xx += 1;
    n++;
  }
  if (bDbl)
  {
  }
  else if (xx > 0)
  {
    for (int i = pD->RecNum-1; i >= 0; i--)
    {
      int rec = GetTermRec(pX, i);
      if (rec != x)
        continue;
      rec = GetTermRec(pY, i);
      if (rec != y)
        continue;
      DeleteRecord(pD, i);
    }
  }
  else
  {
    int num = pD->RecNum;
    DataSet *pDD = pD->item[pX->ip[0]].link;
    int nx = GetDataInt(pDD, x, pDD->posID);
    SetDataInt(pD, num, pX->ip[0], nx);
    pDD = pD->item[pY->ip[0]].link;
    int ny = GetDataInt(pDD, y, pDD->posID);
    SetDataInt(pD, num, pY->ip[0], ny);
  }
  Renew();
  InvalidateRect(hMainWnd, NULL, TRUE);
}


void OnCross(Cell *p, int x, int y)
{
  TCHAR ss[100]; wsprintf(ss, _T("%d %d"), x, y); SetWindowText(hMainWnd, ss); ///////
}

void OnLButtonUp(HWND hWnd, int x, int y)
{
  ReleaseCapture();

  if (curHyperAra)
  {
    Renew();
    InvalidateRect(hWnd, NULL, TRUE);
    return;
  }
  if (curOnClick)
  {
    OnClickCreature(curOnClick);
    curOnClick = NULL;
    return;
  }
  if (cellAt && cellAt->pCrossItem && cellAt->pCrossItem->bOnOff)
  {
    FlipCross(cellAt, cellX, cellY);
    return;
  }

  if (cellAt && cellAt->pCrossItem)
  {
    OnCross(cellAt, cellX, cellY);
    return;
  }
        
  if (hEdit)
  {
    EndInplace(hWnd, TRUE);
    return;
  }
  if (pDStd)
  {
    if (posStd < 0 || bNoInplace)
    {
      int ret = StdInputDialog(hWnd, recStd);
      if (ret != IDCANCEL)
      {
        Renew();
        InvalidateRect(hWnd, NULL, TRUE);
      }
      return;
    }
    else
    {
      int type = pDStd->item[posStd].type;
      switch (type)
      {
      case FT_STR:
        lstrcpy(strOn, GetDataStr(pDStd, insRec, posStd));
        break;
      case FT_INT:
        wsprintf(strOn, _T("%d"), GetDataInt(pDStd, insRec, posStd));
        break;
      case FT_DBL:
        wsprintf(strOn, _T("%s"), ValToStr(GetDataDbl(pDStd, insRec, posStd), 10, FALSE)); // 10 ???????????
        break;
      case FT_LINK:
        GoLink(hWnd, 1);
        return;
      }
      BeginInplace(hWnd);
      return;
    }
  }
  if (pVarAt)
  {
    switch (pVarAt->type)
    {
    case VT_INT:
      wsprintf(strOn, _T("%d"), pVarAt->nVal);
      break;
    case VT_DBL:
      _stprintf_s(strOn, _T("%.15g"), pVarAt->dVal);
      break;
    case VT_STR:
      lstrcpy(strOn, pVarAt->str);
      break;
    default:
      return;
    }
    BeginInplace(hWnd);
    pVarOn = pVarAt;
    return;
  }
  if (pSetOn)
  {
    curSet = pSetOn;
    pSetOn = NULL;
    Renew();
    InvalidateRect(hMainWnd, NULL, TRUE);
    return;
  }
  Renew();
  InvalidateRect(hMainWnd, NULL, TRUE);
}

static int xOld, yOld;

void OnLButtonDown(HWND hWnd, int x, int y)
{
//  if (x < 600)
  //  SetCapture(hWnd);
  xOld = x;
  yOld = y;
}

BOOL OnMouseMoveSet(HWND hWnd, int x, int y)
{
  Set *pSetNow = NULL;
  for (Set *p = topSet->next; p; p = p->next)
  {
    if (p->x1 < x && x < p->x2 && p->y1 < y && y < p->y2)
    {
      pSetNow = p;
      break;
    }
  }

  if (pSetOn != pSetNow)
  {
    HDC hDC = GetDC(hWnd);
    HFONT hFont = GetDefFont(FALSE, TRUE);
    PushFont(hFont, hDC);
    if (pSetOn)
    {
      SetTextColor(hDC, pSetOn == curSet ? RGB(0, 0, 255) : RGB(0, 0, 0));
      TextOut(hDC, pSetOn->x1, pSetOn->y1, pSetOn->name, lstrlen(pSetOn->name));
    }
    if (pSetNow)
    {
      SetTextColor(hDC, RGB(255, 0, 255));
      TextOut(hDC, pSetNow->x1, pSetNow->y1, pSetNow->name, lstrlen(pSetNow->name));
    }
    pSetOn = pSetNow;
    PopFont(hDC);
    ReleaseDC(hWnd, hDC);
  }

  if (pSetOn)
    SetCursor(LoadCursor(NULL, IDC_HAND));
  return pSetOn != NULL;
}

BOOL OnMouseMoveCell(HWND hWnd, int x, int y, Ara *p)
{
  if (hEdit)
    return FALSE;
  pDStd = NULL;
  cellAt = NULL;
  if (!p->pMom || !p->pMom->pCell)
    return FALSE;
  Cell *pCell = p->pMom->pCell;
  int x0 = PixX(p->pMom->x, FALSE);
  int y0 = PixY(p->pMom->y, FALSE, TRUE);
  double dy = defFontSize*0.5;     //////////////  for now
  int h = PixY(dy, FALSE, FALSE);
  int ny = CellLen(pCell);
  if (y < y0)
    return FALSE;
  int yAt = (y - y0) / h;
  if (yAt >= ny)
    return FALSE;
  if (x < x0)
    return FALSE;
  yy0 = y0 + yAt*h;
  yy1 = h;
  int nx = CellWid(pCell);
  int atW = 0, atX = -1;
  for (int j = 0; j < nx; j++)
  {
    xx0 = x0 + atW;
    double wid = CellWidOne(p->pMom->pCell, j);
    int dx = PixX(fabs(wid), FALSE);
    xx1 = dx;
    atW += dx;
    if (x < x0 + atW)
    {
      atX = j;
      break;
    }
  }
  if (atX >= 0)
  {
    if (pCell->type == ST_TABLE)
    {
      bNoInplace = FALSE;
      if (pCell->pD->type == TK_LIST)
        return FALSE;
      pDStd = pCell->pD;
      if (yAt > 0)
      {
        if (pCell->pShow && (yAt - 1) < pCell->nShow)
          insRec = recStd = pCell->pShow[yAt - 1];
        else
          insRec = recStd = yAt - 1;
      }
      else
        insRec = recStd = pDStd->RecNum;
      posStd = -1;
      if (pCell->pTableItem && pCell->nItem > 0 && atX < pCell->nItem)
      {
        TableItem *pTab = &pCell->pTableItem[atX];
        if (pTab->type == TI_PATH)
        {
          if (yAt > 0)
          {
            Path *p = pTab->pPath;
            int len = p->len;
            int type = PathType(p);
            if (len == 1 || len == 2 && type == FT_STR)
            {
              posStd = p->ip[0];
              SetCursor(LoadCursor(NULL, IDC_ARROW));
            }
          }
          else
            SetCursor(LoadCursor(NULL, IDC_ARROW));
        }
        else if (pTab->type == TI_EXPR)
        {
          SetCursor(LoadCursor(NULL, IDC_ARROW));
        }
        else if (pTab->type == TI_NUM)
        {
          if (yAt > 0)
          {
            SetCursor(LoadCursor(NULL, IDC_HAND));
          }
          else
            SetCursor(LoadCursor(NULL, IDC_ARROW));
        }
      }
      else if (atX == 0)
      {
        SetCursor(LoadCursor(NULL, IDC_HAND));
      }
      else
      {
        if (yAt == 0)
          return FALSE;
        int type = -1;
        if (pDStd)
          type = pDStd->item[atX - 1].type;
        if (type == FT_LINK || type == FT_INT)
        {
          SetCursor(LoadCursor(NULL, IDC_ARROW));
          posStd = -1;
          posStd = atX - 1; ///////
    //      bNoInplace = TRUE;
        }
        else if (type == FT_STR || type  == FT_DBL)
        {
          SetCursor(LoadCursor(NULL, IDC_IBEAM));
          posStd = atX - 1;
        }
        else
        {
          SetCursor(LoadCursor(NULL, IDC_HAND));
        }
      }
      return TRUE;
    }
    else if (pCell->type == ST_CROSS)
    {
      if (pCell->pCrossItem->bOnOff && atX > 0 && yAt > 0)
      {
        cellAt = pCell;
        cellX = atX-1;
        cellY = yAt-1;
        SetCursor(LoadCursor(NULL, IDC_HAND));
        return TRUE;
      }
      if (pCell->pCrossItem->pX && pCell->pCrossItem->pY)
      {
        int nx = PathWid(pCell->pCrossItem->pX);
        int ny = PathWid(pCell->pCrossItem->pY);
        if (atX > 0 && atX <= nx && yAt > 0 && yAt <= ny)
        {
          cellAt = pCell;
          cellX = atX - 1;
          cellY = yAt - 1;
          SetCursor(LoadCursor(NULL, IDC_HAND));
          return TRUE;
        }
      }
      return FALSE;
    }
    int at = yAt*nx + atX;
    if (at < pCell->nItem && pCell->pCellItem[at]->type == ITEM_VAR)
    {
      SetCursor(LoadCursor(NULL, IDC_IBEAM));
      pVarAt = pCell->pCellItem[at]->pVar;
      return TRUE;
    }
  }
  return FALSE;
}

BOOL OnMouseMoveOnClick(int x, int y)
{
  curOnClick = NULL;
  for (OnClick *p = topOnClick; p; p = p->next)
  {
    if (p->x1 < x && x < p->x2 && p->y1 < y && y < p->y2)
    {
 //     TCHAR ss[100]; wsprintf(ss, _T("%d"), p->start); SetWindowText(hMainWnd, ss); //////////////////
      curOnClick = p;
      SetCursor(LoadCursor(NULL, IDC_HAND));
      return TRUE;
    }
  }
  SetCursor(LoadCursor(NULL, IDC_ARROW));
  return FALSE;
}

void OnMouseMove(HWND hWnd, int x, int y)
{
  curOnClick = NULL;
  if (CheckHyper(x, y))
    return;

  if (OnMouseMoveOnClick(x, y))
    return;

  if (OnMouseMoveSet(hWnd, x, y))
    return;

  BOOL bCursor = FALSE;
  pVarAt = NULL;
  for (int i = numAra-1; i >= 0; i--)
  {
    Ara *p = &pAra[i];
    if (p->type == ET_CELL)
    {
      if (OnMouseMoveCell(hWnd, x, y, p))
      {
        bCursor = TRUE;
        break;
      }
    }
  }
  curHyperAra = NULL;
  for (int i = 0; i < numHyper; i++)
  {
    Ara *p = pHyper[i];
    Hyper *pp = p->pMom->pHyper;
    if (!pp)
      continue;
    if (pp->x1 < x && pp->y1 < y && pp->x2 > x && pp->y2 > y)
    {
      SetCursor(LoadCursor(NULL, IDC_HAND));
      bCursor = TRUE;
      curHyperAra = p;
      break;
    }
  }
  if (!bCursor)
    SetCursor(LoadCursor(NULL, IDC_ARROW));
}

void OnDestroy(HWND hWnd)
{
  for (DataSet *pD = pDataSetTop; pD; pD = pD->next)
  {
    delete [] pD->RecData;
    pD->RecData = NULL;
  }
  ClearStrIn();
  ClearColor();
  ClearFont();

  Set *pp = topSet, *qq;
  for ( ; pp; pp = qq)
  {
    qq = pp->next;
    ClearSet(pp);
    delete pp;
  }
}

void OnTimerClick(HWND hWnd)
{
  BOOL bSW = FALSE;
  int now = GetTickCount();
  for (OnClick *p = topOnClick; p; p = p->next)
  {
    int time = p->goal > now ? (p->goal - now)/1000 : 0;
    if (time != p->time)
    {
      bSW = TRUE;
      p->time = time;
      RECT rc;
      rc.left = p->x1;
      rc.top = p->y1;
      rc.right = p->x2;
      rc.bottom = p->y2;
      InvalidateRect(hWnd, &rc, TRUE);
 //     TCHAR ss[100]; wsprintf(ss, _T("time %d"), time); SetWindowText(hMainWnd, ss); ////////////
    }
  }
  if (bSW)
    Renew();
}

void OnTimer(HWND hWnd)
{
  static int nn;
  nn++;
  if (nn >= 10)
  {
    nn = 0;
    OnTimerClick(hWnd);
  }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        int wmId, wmEvent;
        PAINTSTRUCT ps;
        HDC hdc;
  int ret;

        switch (message)
        {
  case WM_CREATE:
    OnCreate(hWnd);
    break;
  case WM_TIMER:
    OnTimer(hWnd);
    break;
  case WM_MOUSEWHEEL:
    OnWheel(hWnd, wParam, lParam);
    break;
  case WM_MOUSEMOVE:
    OnMouseMove(hWnd, (short)LOWORD(lParam), (short)HIWORD(lParam));
    break;
  case WM_LBUTTONDOWN:
    OnLButtonDown(hWnd, (short)LOWORD(lParam), (short)HIWORD(lParam));
    break;
  case WM_LBUTTONUP:
    OnLButtonUp(hWnd, (short)LOWORD(lParam), (short)HIWORD(lParam));
    break;
  case WM_RBUTTONUP:
    OnRButtonUp(hWnd, (short)LOWORD(lParam), (short)HIWORD(lParam));
    break;
        case WM_COMMAND:
                wmId    = LOWORD(wParam);
                wmEvent = HIWORD(wParam);
                // 選択されたメニューの解析:
                switch (wmId)
                {
                case IDM_ABOUT:
                        DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                        break;
    case IDM_FULL:
      ret = DialogBox(hInst, MAKEINTRESOURCE(IDD_FULL), hWnd, EditArasi);
      break;
                case IDM_EXIT:
      PostMessage(hWnd, WM_CLOSE, 0, 0);
                        break;
    case IDM_OPEN:
      OnOpenA(hWnd);
      break;
    case IDM_SAVE:
      OnSaveA(hWnd, TRUE);
      break;
    case IDM_SAVEAS:
      OnSaveA(hWnd, FALSE);
      break;
    case IDM_OPEN_D:
      OnOpenD(hWnd);
      break;
    case IDM_SAVE_D:
      OnSaveD(hWnd);
      break;
    case IDM_SAVEAS_D:
      OnSaveAsD(hWnd);
      break;
    case IDM_PRINT:
      OnPrint(hWnd);
      break;

                default:
                        return DefWindowProc(hWnd, message, wParam, lParam);
                }
                break;
        case WM_PAINT:
                hdc = BeginPaint(hWnd, &ps);
    rcp = ps.rcPaint;

    OnPaint(hWnd, hdc, FALSE);
                EndPaint(hWnd, &ps);
                break;
        case WM_DESTROY:
    OnDestroy(hWnd);
                PostQuitMessage(0);
                break;
  case WM_CLOSE:
    OnClose(hWnd);
    break;
        default:
                return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
}

typedef struct tagDbl
{
  double val;
  struct tagDbl *next;
} Dbl;

int lenE, maxE;
int *ipE;
Dbl *topDbl;


Dbl *NewDbl(double val)
{
  Dbl *p = new Dbl;
  p->val = val;
  p->next = topDbl;
  topDbl = p;
  return p;
}

void AddE(int code)
{
  if (lenE >= maxE)
  {
    maxE += 32;
    int *ip = new int[maxE];
    ZeroMemory(ip, sizeof(int)*maxE);
    for (int i = 0; i < lenE; i++)
      ip[i] = ipE[i];
    if (ipE)
      delete [] ipE;
    ipE = ip;
  }
  ipE[lenE++] = code;
}

BOOL Prim()
{
  Variable *pVar;
  Path *pPath;
  TCHAR *str;

  int token = GetToken();
  switch (token)
  {
  case TK_INT:
    AddE(token);
    AddE(nVal);
    break;
  case TK_DBL:
    AddE(token);
    AddE(int(NewDbl(dVal)));
    break;
  case TK_MINUS:
    if (Prim())
      return TRUE;
    AddE(TK_NEG);
    break;
  case TK_BEGINNAME:
    if (CheckToken(TK_STR))
      return TRUE;
    pPath = FindPath(pDStd, strIn);
    if (!pPath)
    {
      lstrcpy(strErrMsg, _T("cannot found path in Prim"));
      return TRUE;
    }
    AddE(TK_PATH);
    AddE((int)pPath);
    if (CheckToken(TK_ENDNAME))
      return TRUE;
    break;
  case TK_AT:
    if (CheckToken(TK_IN))
      return TRUE;
    if (CheckToken(TK_STR))
      return TRUE;
    pVar = FindVar(strIn);
    if (!pVar)
    {
      wsprintf(strErrMsg, _T("Variable %s not found in Prim"), strIn);
      return TRUE;
    }
    AddE(token);
    AddE(int(pVar));
    if (CheckToken(TK_OUT))
      return TRUE;
    break;
  case TK_ID:
    pVar = FindVar(nameIn);
    if (!pVar)
    {
      wsprintf(strErrMsg, _T("Variable %s is not found in Prim"), nameIn);
      return TRUE;
    }
    AddE(token);
    AddE(int(pVar));
    break;
  case TK_IN:
    if (ParseE())
      return TRUE;
    if (CheckToken(TK_OUT))
      return TRUE;
    break;
  case TK_STR:
    str = new TCHAR[lstrlen(strIn) + 1];
    lstrcpy(str, strIn);
    AddE(token);
    AddE(int(str));
    break;

  default:
    wsprintf(strErrMsg, _T("bad token %s in Prim"), TokenStr(token));
    return TRUE;
  }
  return FALSE;
}

BOOL Factor()
{
  if (Prim())
    return TRUE;
  while (1)
  {
    int token = GetToken();
    if (token == TK_POW)
    {
      if (Prim())
        return TRUE;
      AddE(token);
    }
    else
    {
      UngetToken(token);
      break;
    }
  }
  return FALSE;
}

BOOL Term()
{
  if (Factor())
    return TRUE;
  while (1)
  {
    int token = GetToken();
    if (token == TK_MULTI || token == TK_DIV || token == TK_MOD || token == TK_NDIV)
    {
      if (Factor())
        return TRUE;
      AddE(token);
    }
    else
    {
      UngetToken(token);
      break;
    }
  }
  return FALSE;
}

BOOL ExprA()
{
  if (Term())
    return TRUE;
  while (1)
  {
    int token = GetToken();
    if (token == TK_PLUS || token == TK_MINUS)
    {
      if (Term())
        return TRUE;
      AddE(token);
    }
    else
    {
      UngetToken(token);
      break;
    }
  }
  return FALSE;
}

BOOL ExprR()
{
  if (ExprA())
    return TRUE;
  while (1)
  {
    int token = GetToken();
    switch (token)
    {
    case TK_EQ: case TK_NE: case TK_LE: case TK_LT: case TK_GE: case TK_GT:
      if (ExprA())
        return TRUE;
      AddE(token);
      break;
    default:
      UngetToken(token);
      return FALSE;
    }
  }
  return FALSE;
}

BOOL ExprAnd()
{
  if (ExprR())
    return TRUE;
  while (1)
  {
    int token = GetToken();
    if (token == TK_AND)
    {
      if (ExprR())
        return TRUE;
      AddE(token);
    }
    else
    {
      UngetToken(token);
      break;
    }
  }
  return FALSE;
}

BOOL ExprOr()
{
  if (ExprAnd())
    return TRUE;
  while (1)
  {
    int token = GetToken();
    if (token == TK_OR)
    {
      if (ExprAnd())
        return TRUE;
      AddE(token);
    }
    else
    {
      UngetToken(token);
      break;
    }
  }
  return FALSE;
}

BOOL ParseE()
{
  if (ExprOr())
    return TRUE;
  return FALSE;
}

BOOL GetExpr(Expr *p)
{
  bInExpr = TRUE;
  BOOL ret = ParseE();
  bInExpr = FALSE;
  if (ret)
    return TRUE;
  p->len = lenE;
  p->ip = new int[lenE];
  for (int i = 0; i < lenE; i++)
    p->ip[i] = ipE[i];
  ZeroMemory(ipE, lenE*sizeof(int));
  lenE = 0;
  return FALSE;
}

typedef struct
{
  int type;
  int nVal;
  double dVal;
  TCHAR *str;
} EV;

int sp, spMax;
EV *stack;
int typeE;
TCHAR *strPop;

void Push(int type, int nVal, double dVal, TCHAR *str = NULL)
{
  if (sp >= spMax)
  {
    spMax += 32;
    EV *p = new EV[spMax];
    for (int i = 0; i < sp; i++)
      p[i] = stack[i];
    if (stack)
      delete [] stack;
    stack = p;
  }
  EV *p = &stack[sp++];
  p->type = type;
  p->nVal = nVal;
  p->dVal = dVal;
  p->str = str;
}

void Pop()
{
  if (sp > 0)
  {
    sp--;
    typeE = stack[sp].type;
    nVal = stack[sp].nVal;
    dVal = stack[sp].dVal;
    strPop = stack[sp].str;
  }
  else
    lstrcpy(strErrMsg, _T("stack under"));
}

int Eval(Expr *p)
{
  if (!p->ip || p->len == 0)
  {
    nVal = p->len;
    dVal = p->len;
    return EX_THRU;
  }

  int n, t, type;
  double x;
  TCHAR *str;
  Variable *pVar;
  Path *pPath;

  for (int i = 0; i < p->len; i++)
  {
    int tt = p->ip[i];
    switch (tt)
    {
    case TK_INT:
      n = p->ip[++i];
      Push(TK_INT, n, n);
      break;
    case TK_DBL:
      x = ((Dbl*)p->ip[++i])->val;
      Push(TK_DBL, (int)x, x);
      break;
    case TK_STR:
      str = (TCHAR*)p->ip[++i];
      Push(TK_STR, 0, 0, str);
      break;
    case TK_AT:
      pVar = ((Variable*)p->ip[++i]);
      Push(pVar->type == VT_DBL ? TK_DBL : TK_INT, pVar->nVal, pVar->dVal);
      break;
    case TK_PATH:
      pPath = ((Path*)p->ip[++i]);
      type = PathType(pPath);
      if (type == FT_DBL)
      {
        x = GetPathDbl(pPath, evalRec);
        Push(TK_DBL, (int)x, x);
      }
      else if (type == FT_STR)
      {
        str = GetPathStr(pPath, evalRec);
        Push(TK_STR, 0, 0, str);
      }
      else if (type == FT_LINK)
      {
        n = GetPathInt(pPath, evalRec);
        str = GetPathExt(pPath, evalRec);
        Push(TK_INT, n, n, str);
      }
      else
      {
        n = GetPathInt(pPath, evalRec);
        Push(TK_INT, n, n);
      }
      break;
    case TK_NEG:
      Pop();
      Push(typeE, -nVal, -dVal);
      break;
    case TK_POW:
      Pop();
      x = dVal;
      Pop();
      x = pow(dVal, x);
      Push(TK_DBL, (int)x, x);
      break;
    case TK_MULTI:
      Pop();
      x = dVal;
      n = nVal;
      t = typeE;
      Pop();
      if (t == TK_INT && typeE == TK_INT)
        t = TK_INT;
      else
        t = TK_DBL;
      Push(t, n*nVal, x*dVal);
      break;
    case TK_DIV: case TK_NDIV:
      Pop();
      x = dVal;
      n = nVal;
      t = typeE;
      if (t == TK_INT && n == 0 || t == TK_DBL && x == 0)
      {
        lstrcpy(strErrMsg, _T("div by zero"));
      }
      if (x == 0)
        x = 1;
      if (n == 0)
        n = 1;
      Pop();
      if (t == TK_INT && typeE == TK_INT)
        t = TK_INT;
      else
        t = TK_DBL;
      if (tt == TK_NDIV)
        Push(TK_INT, nVal/n, nVal/n);
      else
        Push(t, nVal/n, dVal/x);
      break;
    case TK_MOD:
      Pop();
      n = nVal;
      if (n == 0)
      {
        lstrcpy(strErrMsg, _T("div by zero"));
        n = 1;
      }
      Pop();
      Push(TK_INT, nVal%n, nVal%n);
      break;
    case TK_PLUS:
      Pop();
      x = dVal;
      n = nVal;
      t = typeE;
      Pop();
      if (t == TK_INT && typeE == TK_INT)
        t = TK_INT;
      else
        t = TK_DBL;
      Push(t, n + nVal, x + dVal);
      break;
    case TK_MINUS:
      Pop();
      x = dVal;
      n = nVal;
      t = typeE;
      Pop();
      if (t == TK_INT && typeE == TK_INT)
        t = TK_INT;
      else
        t = TK_DBL;
      Push(t, nVal - n, dVal - x);
      break;
    case TK_AND:
      Pop();
      n = nVal;
      Pop();
      n = n && nVal;
      Push(TK_INT, n, n);
      break;
    case TK_OR:
      Pop();
      n = nVal;
      Pop();
      n = n || nVal;
      Push(TK_INT, n, n);
      break;
    case TK_EQ: case TK_NE: case TK_LE: case TK_LT: case TK_GE: case TK_GT:
      Pop();
      x = dVal;
      n = nVal;
      t = typeE;
      str = strPop;
      Pop();
      if (str != NULL && strPop != NULL)
      {
        int cmp = lstrcmp(strPop, str);
        switch (tt)
        {
        case TK_EQ:
          n = !cmp;
          break;
        case TK_NE:
          n = cmp != 0;
          break;
        case TK_LE:
          n = cmp <= 0;
          break;
        case TK_LT:
          n = cmp < 0;
          break;
        case TK_GE:
          n = cmp >= 0;
          break;
        case TK_GT:
          n = cmp > 0;
          break;
        }
        Push(TK_INT, n, n);
      }
      else
      {
        if (t == TK_INT && typeE == TK_INT)
          t = TK_INT;
        else
          t = TK_DBL;
        switch (tt)
        {
        case TK_EQ:
          t = t == TK_INT ? (n == nVal) : (x == dVal);
          break;
        case TK_NE:
          t = t == TK_INT ? (n != nVal) : (x != dVal);
          break;
        case TK_LE:
          t = t == TK_INT ? (nVal <= n) : (dVal <= x);
          break;
        case TK_LT:
          t = t == TK_INT ? (nVal < n) : (dVal < x);
          break;
        case TK_GE:
          t = t == TK_INT ? (nVal >= n) : (dVal >= x);
          break;
        case TK_GT:
          t = t == TK_INT ? (nVal > n) : (dVal > x);
          break;
        }
        Push(TK_INT, t, t);
      }
      break;
    }
  }
  Pop();
  if (typeE == TK_INT)
  {
    dVal = nVal;
    return EX_INT;
  }
  if (typeE == TK_DBL)
  {
    nVal = (int)dVal;
    return EX_DBL;
  }
  if (typeE == TK_STR)
  {
    return EX_STR;
  }

  return EX_ERR;
}

void UnLocal(TCHAR *str)
{
  static TCHAR *zen[] =
  { _T("0"), _T("1"), _T("2"), _T("3"), _T("4"), _T("5"), _T("6"), _T("7"),
    _T("8"), _T("9"), _T("."), _T("+"), _T("-"), _T("e"), _T("E"), _T(","), _T("/") };
  TCHAR *han = _T("0123456789.+-e,/");
  int num = sizeof(han)/sizeof(han[0]);

  TCHAR buf[100];
  TCHAR *p = str;
  TCHAR *q = buf;
  /*
  if (IsGengo(*p))
  {
    *q++ = *p++;
  }
  */
  while (*p)
  {
    if (*p == ',')
      p++;
    else if (_istdigit(*p) || *p == '.' ||
             *p == '+' || *p == '-' || *p == 'e' || *p == 'E' || *p == ' ' || *p == ':')
      *q++ = *p++;
    else
    {
      int n = 1;
      int i;
      for (i = 0; i < num; i++)
      {
        n = lstrlen(zen[i]);
        if (!_tcsncmp(p, zen[i], n))
          break;
      }
      if (i < num-1)
        *q++ = han[i];
      p += n;
    }
  }
  *q = 0;
  lstrcpy(str, buf);
}

HWND *hEd;
Force *pForce;

Force *FindForce(int pos)
{
  for (Force *p = pForce; p; p = p->next)
  {
    if (p->pos == pos)
      return p;
  }
  return NULL;
}

void InitStdDlg(HWND hDlg)
{
  BOOL bChange = recStd < pDStd->RecNum;

  hEd = new HWND[pDStd->num];
  ZeroMemory(hEd, sizeof(HWND)*pDStd->num);

  HFONT hFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0);

  HDC hDC = GetDC(hDlg);
  SelectObject(hDC, hFont);
  TEXTMETRIC tm;
  GetTextMetrics(hDC, &tm);
  int cH = tm.tmHeight + tm.tmExternalLeading;          // char height
  int dH = cH*5/2;                                      // one line height
  int eH = cH*5/3;                                      // edit box height
  int yd = (eH-cH)/2;                                   // diff from text to edit box
  int cW = tm.tmAveCharWidth;                           // char width

  // get max width of title
  int wName = 0;
  for (int i = 0; i < pDStd->num; i++)
  {
    if (pDStd->item[i].bTemp)
      continue;
    Force *q = FindForce(i);
    if (q && !q->pList)
      continue;
    SIZE sz;
    TCHAR *p = pDStd->item[i].name;
    GetTextExtentPoint32(hDC, p, lstrlen(p), &sz);
    if (sz.cx > wName)
      wName = sz.cx;
  }
  ReleaseDC(hDlg, hDC);
  hDC = NULL;
  int eWid = 31*cW;                                     // edit box width

  // titles and edit box or combo box
  int nMulti = 0;
  int nH = 0;
  for (int i = 0; i < pDStd->num; i++)
  {
    if (pDStd->item[i].bTemp)
      continue;
    Force *p = FindForce(i);
    if (p && !p->pList)
    {
      hEd[i] = NULL;
      continue;
    }

    // title
    HWND hSt = CreateWindow(_T("static"), pDStd->item[i].name, 
      WS_CHILD | WS_VISIBLE | SS_RIGHT | SS_NOPREFIX,
      cW*2, cH+dH*(nH+nMulti)+yd, wName, eH, hDlg, (HMENU)-1, hInst, NULL);
    SendMessage(hSt, WM_SETFONT, (WPARAM)hFont, 0);

    int type = pDStd->item[i].type;
    BOOL bMulti = type == FT_STRMUL;

    // combo box
    if (type == FT_LINK)
    {
      hEd[i] = CreateWindow(_T("combobox"), _T(""),
          WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | WS_VSCROLL | 
          CBS_AUTOHSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
          cW*3+wName, cH+dH*(nH+nMulti), eWid, eH*10, hDlg, (HMENU)(1000+i), hInst, NULL);

      DataSet *pLink = pDStd->item[i].link;
      int num = p && p->pList ? p->nList : pLink->RecNum;
      for (int j = 0; j < num; j++)
      {
        int at = j;
        if (p && p->pList)
        {
          int n = p->pList[j];
          at = FindIDData(pLink, n);
        }
        TCHAR buf[100];
        TCHAR *str = _T("");
        if (pLink->posName >= 0)
          str = GetDataStr(pLink, at, pLink->posName);
        else
        {
          wsprintf(buf, _T("[%d]"), pLink->posID < 0 ? at : GetDataInt(pLink, at, pLink->posID));
          str = buf;
        }
        SendMessage(hEd[i], CB_ADDSTRING, 0, (LPARAM)str);
      }

      // selection
      int add = 0;
      int at = 0;
      if (recStd < pDStd->RecNum)
      {
        int n = GetDataInt(pDStd, recStd, i);
        if (p && p->pList)
        {
          for (int k = 0; k < p->nList; k++)
          {
            if (n == p->pList[k])
              at = k;
          }
        }
        else
          at = FindIDData(pLink, n);
      }
      else
      {
        int ini = 0; //////////////
        if (ini > 0)
        {
          int n = FindIDData(pLink, ini);
          if (n >= 0)
            at = n;
        }
      }

      if (at < 0)
        at = -add;
      SendMessage(hEd[i], CB_SETCURSEL, (WPARAM)(at + add), 0);
    }

    // edit box
    else
    {
      TCHAR buf[64];
      buf[0] = 0;
      TCHAR *data = buf;

      // old data
      if (recStd < pDStd->RecNum)
      {
        data = GetDataAsStr(pDStd, recStd, i, FALSE);
 //       if (type == TK_DATEDATA && !_tcscmp(data, _T("0")))
   //       data = _T("");
      }
      else if (type == FT_ID)
      {
        wsprintf(buf, _T("%d"), NextID(pDStd, FALSE));
      }

      int eHH = bMulti ? dH + eH : eH;
      int style = !bMulti ? WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP :
                            WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP |
                            ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL;
      hEd[i] = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_NOPARENTNOTIFY,
          _T("edit"), data, style,
          cW*3+wName, cH+dH*(nH+nMulti), eWid, eHH, hDlg, (HMENU)(1000+i), hInst, NULL);
    }
    SendMessage(hEd[i], WM_SETFONT, (WPARAM)hFont, 0);

    if (bMulti)
      nMulti++;
    nH++;
  }

  // dialog size
  int y = cH+dH*(nH + nMulti) + eH/2;            // button position
  int DlgW = cW*6+wName+eWid;
  int DlgH = y+eH*9/2;

  // OK, Cancel buttons
  int x0 = (DlgW - cW*36)/2;
  HWND hRet = GetDlgItem(hDlg, IDOK);
  MoveWindow(hRet, x0, y, cW*10, eH, FALSE);
  HWND hIns = GetDlgItem(hDlg, IDC_INS);
  MoveWindow(hIns, x0+cW*13, y, cW*10, eH, FALSE);
  HWND hChg = GetDlgItem(hDlg, IDC_CHG);
  MoveWindow(hChg, x0+cW*26, y, cW*10, eH, FALSE);
  HWND hCan = GetDlgItem(hDlg, IDCANCEL);
  MoveWindow(hCan, x0+cW*7, y+eH*3/2, cW*10, eH, FALSE);
  HWND hDel = GetDlgItem(hDlg, IDC_DELETE);
  MoveWindow(hDel, x0+cW*20, y+eH*3/2, cW*10, eH, FALSE);
  SendMessage(hRet, WM_SETFONT, (WPARAM)hFont, 0);
  SendMessage(hIns, WM_SETFONT, (WPARAM)hFont, 0);
  SendMessage(hChg, WM_SETFONT, (WPARAM)hFont, 0);
  SendMessage(hCan, WM_SETFONT, (WPARAM)hFont, 0);
  SendMessage(hDel, WM_SETFONT, (WPARAM)hFont, 0);

  EnableWindow(hIns, pDStd->posID < 0);
//  EnableWindow(hDel, bChange); /////////////////////////

  RECT rc;
  GetWindowRect(hDlg, &rc);
  MoveWindow(hDlg, rc.left, rc.top, DlgW, DlgH, FALSE);

  if (pDStd->item[0].type == FT_LINK)
  {
    SetFocus(hEd[0]);
  }
  else
  {
    SetFocus(hEd[0]);
    SendMessage(hEd[0], EM_SETSEL, 0, -1);
  }
}

// OK button -> update data : if return TRUE, data is bad
static BOOL UpdateStd(HWND hDlg, BOOL bLast)
{
  const int size = 255;
  TCHAR buf[size+1], *pp;
  int id = -1;
  int idOld = -1;
  BOOL bNeedSort = FALSE;
  BOOL bIDChange = FALSE;
  BOOL bAdd = recStd == pDStd->RecNum;

  // check ID dupe
  if (pDStd->posID >= 0 && hEd[pDStd->posID])
  {
    // get ID val
    GetWindowText(hEd[pDStd->posID], buf, size);
    UnLocal(buf);
    id = _tcstol(buf, &pp, 10);

    // changed ?
    if (recStd < pDStd->RecNum)
    {
      int idOld = GetDataInt(pDStd, recStd, pDStd->posID);
      bNeedSort = idOld != id;
    }
    else
      bNeedSort = TRUE;

    // if ID is changed, check dupe
    int at = -1;
    if (bNeedSort)
    {
      at = FindIDData(pDStd, id);
      if (at >= 0)
        MessageBox(hDlg, _T("IDが重複しています"), _T("Error"), MB_OK);
    }

    // if duped, return TRUE
    if (at >= 0)
    {
      HWND h = hEd[pDStd->posID];
      wsprintf(buf, _T("%d"), NextID(pDStd, FALSE));
      SetWindowText(h, buf);
      SetFocus(h);
      SendMessage(h, EM_SETSEL, 0, -1);
      return TRUE;
    }

    // if ID has changed, linker also change
    if (recStd < pDStd->RecNum && id != idOld)
    {
      bIDChange = TRUE;                            // just flag, it may be canceled
    }
  }

  // check has passed, so update all
  for (int i = 0; i < pDStd->num; i++)
  {
    if (pDStd->item[i].bTemp)
      continue;
    Force *p = FindForce(i);
    if (!hEd[i])
    {
      {
        switch (pDStd->item[i].type)
        {
        case FT_LINK: case FT_DATE: case FT_INT:
          SetDataInt(pDStd, recStd, i, p->nVal);
          break;
        case FT_DBL:
          SetDataDbl(pDStd, recStd, i, p->dVal);
          break;
        case FT_STR: case FT_STRMUL:
          SetDataStr(pDStd, recStd, i, p->str);
          break;
        }
      }
    }
    else if (pDStd->item[i].type == FT_LINK)
    {
      DataSet *pD = pDStd->item[i].link;
      int at = SendMessage(hEd[i], CB_GETCURSEL, 0, 0);
      int n = p && p->pList ? p->pList[at] : (pD->posID < 0 ? at : GetDataInt(pD, at, pD->posID));
      SetDataInt(pDStd, recStd, i, n);
    }
    else
    {
      GetWindowText(hEd[i], buf, size);
      switch (pDStd->item[i].type)
      {
      case FT_DBL:
        UnLocal(buf);
        SetDataDbl(pDStd, recStd, i, _tcstod(buf, &pp));
        break;
      case FT_DATE:
        UnLocal(buf);
        SetDataInt(pDStd, recStd, i, StrToDate(buf));
        break;
      case FT_ID: case FT_INT:
        UnLocal(buf);
        SetDataInt(pDStd, recStd, i, _tcstol(buf, &pp, 10));
        break;
      case FT_STR: case FT_STRMUL:
        SetDataStr(pDStd, recStd, i, buf);
        break;
      }
    }
  }

  if (!bLast && bAdd && recStd != insRec)
  {
    SwapRecTo(pDStd, insRec);
  }

//  bPoll = TRUE;
  return FALSE;
}

void EndStdDlg(HWND hDlg, int id)
{
  EndDialog(hDlg, id);
  if (hEd)
  {
    delete [] hEd;
    hEd = NULL;
  }
}

LRESULT CALLBACK StdDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
  int id = LOWORD(wParam);
  switch( message )
  {
  case WM_INITDIALOG:
    InitStdDlg(hDlg);
    return FALSE;

  case WM_COMMAND:
    switch (id)
    {
    case IDOK:  // 追加
      recStd = pDStd->RecNum;
      if (UpdateStd(hDlg, TRUE))
        return TRUE;
      EndStdDlg(hDlg, id);
      return TRUE;
    case IDCANCEL:
      EndStdDlg(hDlg, id);
      return TRUE;
    case IDC_INS:
      recStd = pDStd->RecNum;
      if (UpdateStd(hDlg, FALSE))
        return TRUE;
      EndStdDlg(hDlg, id);
      return TRUE;
    case IDC_CHG:
      if (UpdateStd(hDlg, FALSE))
        return TRUE;
      EndStdDlg(hDlg, id);
      return TRUE;
    case IDC_DELETE:
      DeleteRecord(pDStd, insRec);
      EndStdDlg(hDlg, id);
      return TRUE;
    default:
      break;
    }
    break;
  }
  return FALSE;
}

int StdInputDialog(HWND hWnd, int rec)
{
  int ret = DialogBox(hInst, (LPCTSTR)IDD_DEFAULT, hWnd, (DLGPROC)StdDlgProc);

  return ret;
}