#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include "resource.h"
#include "afxres.h"
#include "list.h"

typedef struct tagAPPLINFO
{
  char szAppName[40];
  char szIconName[20];
  UINT iCost;
}APPLINFO;

// -----------------------------------------------------
// Глобальные переменные
// -----------------------------------------------------
APPLINFO rgApplInfo[]=
{
  {"Generic",           "appicon.ico ",   5},
  {"Book",              "book1.ico   ",   2},
  {"Driver List",       "drvlist.ico ",  22},
  {"MCI CD Player",     "mcicdpl.ico ", 345},
  {"MCI String Player", "mcistrvw.ico",  54},
  {"MCI Wave Player",   "mciwaver.ico",  32},
  {"MCI Window Demo",   "mciwnd.ico  ",   0},
  {"Sound Play",        "sndplay.ico ",   0},
  {"Wave Play",         "wave.ico    ",   4}
};

HINSTANCE hInst;
char szAppName[] = "ListApp";
char szAppTitle[] = "List Application";
HWND hwndList;

// -----------------------------------------------------
// Функция WinMain
// -----------------------------------------------------
int APIENTRY 
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc;
  HWND hWnd;
  MSG msg;
  
  hInst = hInstance;

  // Преверяем, не было ли это приложение запущено ранее
  hWnd = FindWindow(szAppName, NULL);
  if(hWnd)
  {
    if(IsIconic(hWnd))
	  ShowWindow(hWnd, SW_RESTORE);
	SetForegroundWindow(hWnd);
    return FALSE;
  }


  // Регистрируем класс окна
  memset(&wc, 0, sizeof(wc));
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.hIconSm = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICONSM), IMAGE_ICON, 16, 16, 0);
  wc.style = 0;
  wc.lpfnWndProc = (WNDPROC)WndProc;
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.hInstance = hInst;
  wc.hIcon = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, 0);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = MAKEINTRESOURCE(IDR_APPMENU);
  wc.lpszClassName = szAppName;
  if(!RegisterClassEx(&wc))
    if(!RegisterClass((LPWNDCLASS)&wc.style))
	  return FALSE;
    
  // Создаем главное окно приложения
  hWnd = CreateWindow(szAppName, szAppTitle, WS_OVERLAPPEDWINDOW,
   	 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
  if(!hWnd) return(FALSE);

  // Отображаем окно и запускаем цикл обработки сообщений
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
  while(GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// -----------------------------------------------------
// Функция WndProc
// -----------------------------------------------------
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hWnd, WM_CREATE,     WndProc_OnCreate);
    HANDLE_MSG(hWnd, WM_DESTROY,    WndProc_OnDestroy);
    HANDLE_MSG(hWnd, WM_COMMAND,    WndProc_OnCommand);
    HANDLE_MSG(hWnd, WM_NOTIFY,     WndProc_OnNotify);
    HANDLE_MSG(hWnd, WM_SIZE,       WndProc_OnSize);

	default:
      return(DefWindowProc(hWnd, msg, wParam, lParam));
  }
}

// -----------------------------------------------------
// Функция WndProc_OnCreate
// -----------------------------------------------------
BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
  int i;
  RECT rc;
  HIMAGELIST himlSmall;
  HIMAGELIST himlLarge;
  HICON hIcon;
  LV_COLUMN lvc;
  LV_ITEM lvi;

  // Определяем размеры внутренней области главного окна
  GetClientRect(hWnd, &rc);

  // Инициализируем библиотеку стандартных органов управления
  InitCommonControls();

  // Создаем орган управления List View
  hwndList = CreateWindowEx(0L, WC_LISTVIEW, "",
    WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT | 
    LVS_EDITLABELS,
    0, 0, rc.right - rc.left, rc.bottom - rc.top,
    hWnd, (HMENU) IDC_LISTVIEW, hInst, NULL);

  if(hwndList == NULL)
    return FALSE;

  // Создаем список изображений
  himlSmall = ImageList_Create(
    GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
    ILC_MASK, 9, 1);
  himlLarge = ImageList_Create(
    GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
    ILC_MASK, 9, 1);

  for(i = IDI_ICON1; i <= IDI_ICON9; i++)
  {
    hIcon = LoadIcon(hInst, MAKEINTRESOURCE(i));
    ImageList_AddIcon(himlSmall, hIcon);
    ImageList_AddIcon(himlLarge, hIcon);
  }
  
  // Добавляем списки изображений
  ListView_SetImageList(hwndList, himlSmall, LVSIL_SMALL);
  ListView_SetImageList(hwndList, himlLarge, LVSIL_NORMAL);

  // Вставляем столбцы
  memset(&lvc, 0, sizeof(lvc));

  lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  lvc.fmt = LVCFMT_LEFT;
  lvc.cx = (rc.right - rc.left) / 4;
  
  lvc.iSubItem = 0;
  lvc.pszText = "Application Name";
  ListView_InsertColumn(hwndList, 0, &lvc);

  lvc.iSubItem = 1;
  lvc.pszText = "Icon Name";
  ListView_InsertColumn(hwndList, 1, &lvc);

  lvc.iSubItem = 2;
  lvc.pszText = "Cost, USD";
  ListView_InsertColumn(hwndList, 2, &lvc);
  ListView_SetColumnWidth(hwndList, 2, (rc.right - rc.left) / 8);

  // Вставляем строки
  memset(&lvi, 0, sizeof(lvi));

  lvi.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
  lvi.pszText = LPSTR_TEXTCALLBACK;
  
  for(i=0; i<9; i++)
  {
    lvi.iItem = i;
    lvi.iSubItem = 0;
	lvi.cchTextMax = 40;
	lvi.lParam = (LPARAM)&rgApplInfo[i];
	
    lvi.iImage = i;
    ListView_InsertItem(hwndList, &lvi);

    lvi.iItem = i;
    lvi.iSubItem = 1;
    ListView_InsertItem(hwndList, &lvi);

    lvi.iItem = i;
    lvi.iSubItem = 2;
    ListView_InsertItem(hwndList, &lvi);
  }

  return TRUE;
}

// -----------------------------------------------------
// Функция WndProc_OnDestroy
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnDestroy(HWND hWnd)
{
  DestroyWindow(hwndList);
  PostQuitMessage(0);
  return 0L;
}

// -----------------------------------------------------
// Функция WndProc_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnCommand(HWND hWnd, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  DWORD dwStyle = 0;

  switch (id)
  {
  	case ID_OPTIONS_ICONVIEW:
	{
	  dwStyle = GetWindowLong(hwndList, GWL_STYLE);
	  
	  if((dwStyle & LVS_TYPEMASK) != LVS_ICON)
	    SetWindowLong(hwndList, GWL_STYLE, 
	      (dwStyle & ~LVS_TYPEMASK) | LVS_ICON);
	  break;
	}

  	case ID_OPTIONS_SMALLICONVIEW:
	{
	  dwStyle = GetWindowLong(hwndList, GWL_STYLE);
	  
	  if((dwStyle & LVS_TYPEMASK) != LVS_SMALLICON)
	    SetWindowLong(hwndList, GWL_STYLE, 
	      (dwStyle & ~LVS_TYPEMASK) | LVS_SMALLICON);
	  break;
	}
  	
  	case ID_OPTIONS_LISTVIEW:
	{
	  dwStyle = GetWindowLong(hwndList, GWL_STYLE);
	  
	  if((dwStyle & LVS_TYPEMASK) != LVS_LIST)
	    SetWindowLong(hwndList, GWL_STYLE, 
	      (dwStyle & ~LVS_TYPEMASK) | LVS_LIST);
	  break;
	}
  	
  	case ID_OPTIONS_REPORTVIEW:
	{
	  dwStyle = GetWindowLong(hwndList, GWL_STYLE);
	  
	  if((dwStyle & LVS_TYPEMASK) != LVS_REPORT)
	    SetWindowLong(hwndList, GWL_STYLE, 
	      (dwStyle & ~LVS_TYPEMASK) | LVS_REPORT);
	  break;
	}

	case ID_FILE_EXIT:
	  PostQuitMessage(0);
	  return 0L;
	  break;
	  
  	case ID_HELP_ABOUT:
	  break;

  	default:
	  break;
  }
  return FORWARD_WM_COMMAND(hWnd, id, hwndCtl, codeNotify,
    DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnNotify
// -----------------------------------------------------
LRESULT WndProc_OnNotify(HWND hWnd, int idFrom, NMHDR* pnmhdr)
{
  LV_DISPINFO * lpLvdi = (LV_DISPINFO *)pnmhdr;
  APPLINFO * lpAppinfo = (APPLINFO *)(lpLvdi->item.lParam);
  static char szBuf[20];
  NM_LISTVIEW *lpNm = (NM_LISTVIEW *)pnmhdr;

  if(idFrom != IDC_LISTVIEW)
    return 0L;

  switch(pnmhdr->code)
  {
    case LVN_GETDISPINFO:
	{
	  if(lpLvdi->item.mask & LVIF_TEXT)
      {
	    switch(lpLvdi->item.iSubItem)
	    {
	      case 0:
		    lpLvdi->item.pszText = lpAppinfo->szAppName;
		    break;

	      case 1:
		    lpLvdi->item.pszText = lpAppinfo->szIconName;
		    break;

	      case 2:
            itoa(lpAppinfo->iCost, szBuf, 10);
		    lpLvdi->item.pszText = szBuf;
		    break;

		  default:
		    break;
	    }
	    break;
	  }
    }

    case LVN_COLUMNCLICK:
	{
	  ListView_SortItems(lpNm->hdr.hwndFrom, 
	    LVCompareProc, (LPARAM)(lpNm->iSubItem));
	  return 0L;
	  break;
	}

    case LVN_BEGINLABELEDIT:
	{
	  return 0L;
	  break;
	}

    case LVN_ENDLABELEDIT:
	{
	  if((lpLvdi->item.iItem != -1) &&
	     (lpLvdi->item.pszText != NULL))
		 lstrcpy(lpAppinfo->szAppName, lpLvdi->item.pszText);
	  return 0L;
	  break;
	}

    case NM_DBLCLK:
	{
	  int index;
      LV_ITEM lvi;
	  char szBuf[256];

	  strcpy(szBuf, "Selected item:\n");

      // Определяем номер выделенного элемента
      index = ListView_GetNextItem(hwndList,
        -1, LVNI_ALL | LVNI_SELECTED);

      if(index == -1)
	    return 0;

      // Подготавливаем структуру типа LV_ITEM
      // для получения текстовой информации об элементах
      memset(&lvi, 0, sizeof(lvi));
      lvi.mask = LVIF_TEXT;

      // Получаем название элемента
      lvi.iItem = index;
      lvi.iSubItem = 0;
      ListView_GetItem(hwndList, &lvi);
	  strcat(szBuf, lvi.pszText);

      // Получаем текстовую строку, связанную
      // с первым и вторым дополнительным элементом
      lvi.iItem = index;
      lvi.iSubItem = 1;
      ListView_GetItem(hwndList, &lvi);
	  strcat(szBuf, " : ");
      strcat(szBuf, lvi.pszText);

      lvi.iItem = index;
      lvi.iSubItem = 2;
      ListView_GetItem(hwndList, &lvi);
	  strcat(szBuf, " : $");
      strcat(szBuf, lvi.pszText);

	  // Выводим на экран текстовые строки
      // для выбранного элемента
	  MessageBox(hWnd, szBuf, szAppName, MB_OK);
	  return 0L;
	  break;
	}
  }
  return 0L;
}

// -----------------------------------------------------
// Функция WndProc_OnSize       
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
  MoveWindow(hwndList, 0, 0, cx, cy, TRUE);
  return FORWARD_WM_SIZE(hwnd, state, cx, cy, DefWindowProc);
}

// -----------------------------------------------------
// Функция LVCompareProc      
// -----------------------------------------------------
int CALLBACK 
LVCompareProc(LPARAM lParam1, LPARAM lParam2, 
  LPARAM lParamSort)
{
  APPLINFO *pAppInfo1 = (APPLINFO *)lParam1;
  APPLINFO *pAppInfo2 = (APPLINFO *)lParam2;
  LPSTR lpStr1, lpStr2;
  int iResult;

  if(pAppInfo1 && pAppInfo2)
  {
    switch(lParamSort)
	{
	  case 0: 
	    lpStr1 = pAppInfo1->szAppName;
		lpStr2 = pAppInfo2->szAppName;
		iResult = strcmpi(lpStr1, lpStr2);
		break;

	  case 1:  
		lpStr1 = pAppInfo1->szIconName;
		lpStr2 = pAppInfo2->szIconName;
		iResult = lstrcmpi(lpStr1, lpStr2);
		break;

	  case 2:  
		iResult = pAppInfo1->iCost - pAppInfo2->iCost;
		break;

	  default:
		iResult = 0;
		break;
	}
  }
  return(iResult);
}
